Skip to content

Commit

Permalink
Merge branch 'main' into fix-flakey-macro-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rmccar authored Nov 7, 2024
2 parents aea36f3 + 7d9b0ac commit 621bdf3
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 68 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
"express": "^4.17.1",
"front-matter": "^4.0.2",
"fs-extra": "^11.1.1",
"fuse.js": "^3.6.1",
"fuse.js": "^7.0.0",
"glob": "^10.2.3",
"gulp": "^4.0.2",
"gulp-babel": "^8.0.0",
Expand Down
41 changes: 21 additions & 20 deletions src/components/autosuggest/_macro-options.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
| Name | Type | Required | Description |
| ------------------- | ------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| autosuggestData | string | false | URL of the JSON file with the autosuggest data that needs to be searched. Required if not using the address index api |
| allowMultiple | boolean | false | Allows the component to accept multiple selections |
| instructions | string | true | Instructions on how to use the autosuggest that will be read out by screen readers |
| ariaYouHaveSelected | string | true | Aria message to tell the user that they have selected an answer |
| ariaMinChars | string | true | Aria message to tell the user how many characters they need to enter before autosuggest will start |
| minChars | integer | false | Minimum number of characters to run a query. Default is 3 |
| ariaOneResult | string | true | Aria message to tell the user there is only one suggestion left |
| ariaNResults | string | true | Aria message to tell the user how many suggestions are left |
| ariaLimitedResults | string | true | Aria message to tell the user if the results have been limited and what they are limited to |
| moreResults | string | true | Aria message to tell the user to continue to type to refine suggestions |
| noResults | string | true | message to tell the user there are no results |
| tooManyResults | string | false | message to tell the user there are too many results to display and the user should refine the search. This is only required when using the address index api |
| typeMore | string | true | message to encourage the user to enter more characters to get suggestions |
| resultsTitle | string | true | Title of results to be displayed on screen at the top of the results |
| resultsTitleId | string | true | ID for the results title. The ID is used in the results `aria-labelledby` to provide context for the results |
| input | `Input` [_(ref)_](/components/input) | true | Configuration object for the input |
| language | string | false | The ISO 639-1 Code will override the default language in page. Please note that only 'en', 'cy' and 'ni' is currently supported |
| id | string | false | The `id` of the input |
| Name | Type | Required | Description |
| ------------------- | ------------------------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| autosuggestData | string | false | URL of the JSON file with the autosuggest data that needs to be searched. Required if not using the address index api |
| allowMultiple | boolean | false | Allows the component to accept multiple selections |
| instructions | string | true | Instructions on how to use the autosuggest that will be read out by screen readers |
| ariaYouHaveSelected | string | true | Aria message to tell the user that they have selected an answer |
| ariaMinChars | string | true | Aria message to tell the user how many characters they need to enter before autosuggest will start |
| minChars | integer | false | Minimum number of characters to run a query. Default is 3 |
| ariaOneResult | string | true | Aria message to tell the user there is only one suggestion left |
| ariaNResults | string | true | Aria message to tell the user how many suggestions are left |
| ariaLimitedResults | string | true | Aria message to tell the user if the results have been limited and what they are limited to |
| moreResults | string | true | Aria message to tell the user to continue to type to refine suggestions |
| noResults | string | true | message to tell the user there are no results |
| tooManyResults | string | false | message to tell the user there are too many results to display and the user should refine the search. This is only required when using the address index api |
| typeMore | string | true | message to encourage the user to enter more characters to get suggestions |
| resultsTitle | string | true | Title of results to be displayed on screen at the top of the results |
| resultsTitleId | string | true | ID for the results title. The ID is used in the results `aria-labelledby` to provide context for the results |
| input | `Input` [_(ref)_](/components/input) | true | Configuration object for the input |
| language | string | false | The ISO 639-1 Code will override the default language in page. Please note that only 'en', 'cy' and 'ni' is currently supported |
| resultsThreshold | float | false | Option to adjust the search threshold and fuzziness. Accepts a range from 0 to 1, where 0 provides the closest match and 1 allows for more distant matches. Defaults to 0.2. |
| id | string | false | The `id` of the input |
1 change: 1 addition & 0 deletions src/components/autosuggest/_macro.njk
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
data-results-title="{{ params.resultsTitle }}"
data-no-results="{{ params.noResults }}"
data-type-more="{{ params.typeMore }}"
{% if params.resultsThreshold %}data-result-threshold="{{ params.resultsThreshold }}"{% endif %}
{% if params.apiDomain %}data-api-domain="{{ params.apiDomain }}"{% endif %}
{% if params.apiDomainBearerToken %}data-authorization-token="{{ params.apiDomainBearerToken }}"{% endif %}
{% if params.apiManualQueryParams == true %}data-query-params=""{% endif %}
Expand Down
8 changes: 7 additions & 1 deletion src/components/autosuggest/_macro.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ const EXAMPLE_AUTOSUGGEST = {
typeMore: 'Continue entering to get suggestions',
};

const EXAMPLE_AUTOSUGGEST_WITH_RESULTS_THRESHOLD = {
...EXAMPLE_AUTOSUGGEST,
resultsThreshold: 0.5,
};

describe('macro: autosuggest', () => {
it('passes jest-axe checks', async () => {
const $ = cheerio.load(renderComponent('autosuggest', EXAMPLE_AUTOSUGGEST));
Expand All @@ -47,7 +52,7 @@ describe('macro: autosuggest', () => {
});

it('has the provided data attributes', () => {
const $ = cheerio.load(renderComponent('autosuggest', EXAMPLE_AUTOSUGGEST));
const $ = cheerio.load(renderComponent('autosuggest', EXAMPLE_AUTOSUGGEST_WITH_RESULTS_THRESHOLD));

const $element = $('.ons-autosuggest');
expect($element.attr('data-allow-multiple')).toBeUndefined();
Expand All @@ -63,6 +68,7 @@ describe('macro: autosuggest', () => {
expect($element.attr('data-no-results')).toBe('No suggestions found. You can enter your own answer');
expect($element.attr('data-results-title')).toBe('Suggestions');
expect($element.attr('data-type-more')).toBe('Continue entering to get suggestions');
expect($element.attr('data-result-threshold')).toBe('0.5');
});

it('has the `data-allow-multiple` attribute when `allowMultiple` is `true`', () => {
Expand Down
48 changes: 38 additions & 10 deletions src/components/autosuggest/autosuggest.ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export default class AutosuggestUI {
errorAPI,
errorAPILinkText,
typeMore,
customResultsThreshold,
}) {
// DOM Elements
this.context = context;
Expand Down Expand Up @@ -65,6 +66,7 @@ export default class AutosuggestUI {
this.errorAPI = errorAPI || context.getAttribute('data-error-api');
this.errorAPILinkText = errorAPILinkText || context.getAttribute('data-error-api-link-text');
this.typeMore = typeMore || context.getAttribute('data-type-more');
this.customResultsThreshold = customResultsThreshold || context.getAttribute('data-result-threshold');
this.language = context.getAttribute('data-lang');
this.allowMultiple = context.getAttribute('data-allow-multiple') || false;
this.listboxId = this.listbox.getAttribute('id');
Expand Down Expand Up @@ -293,9 +295,30 @@ export default class AutosuggestUI {

async fetchSuggestions(sanitisedQuery, data) {
this.abortFetch();
const results = await runFuse(sanitisedQuery, data, this.lang, this.resultLimit);

const threshold =
this.customResultsThreshold != null && this.customResultsThreshold >= 0 && this.customResultsThreshold <= 1
? this.customResultsThreshold
: 0.2;

let distance;
if (threshold >= 0.6) {
distance = 500;
} else if (threshold >= 0.4) {
distance = 300;
} else {
distance = 100;
}

const results = await runFuse(sanitisedQuery, data, this.lang, threshold, distance);

results.forEach((result) => {
result.sanitisedText = sanitiseAutosuggestText(result[this.lang], this.sanitisedQueryReplaceChars);
const resultItem = result.item ?? result;

result.sanitisedText = sanitiseAutosuggestText(
resultItem[this.lang] ?? resultItem['formattedAddress'],
this.sanitisedQueryReplaceChars,
);
});
return {
status: this.responseStatus,
Expand Down Expand Up @@ -345,16 +368,18 @@ export default class AutosuggestUI {
this.listbox.innerHTML = '';
if (this.results) {
this.resultOptions = this.results.map((result, index) => {
let innerHTML = this.emboldenMatch(result[this.lang], this.query);
const resultItem = result.item ?? result;

let innerHTML = this.emboldenMatch(resultItem[this.lang] ?? resultItem['formattedAddress'], this.query);

const listElement = document.createElement('li');
listElement.className = classAutosuggestOption;
listElement.setAttribute('id', `${this.listboxId}__option--${index}`);
listElement.setAttribute('role', 'option');
if (result.category) {
if (resultItem.category) {
innerHTML =
innerHTML +
`<span class="ons-autosuggest__category ons-u-lighter ons-u-fs-s ons-u-db">${result.category}</span>`;
`<span class="ons-autosuggest__category ons-u-lighter ons-u-fs-s ons-u-db">${resultItem.category}</span>`;
}
listElement.innerHTML = innerHTML;
listElement.addEventListener('click', () => {
Expand Down Expand Up @@ -485,16 +510,19 @@ export default class AutosuggestUI {
if (this.results.length) {
this.settingResult = true;
const result = this.results[index || this.highlightedResultIndex || 0];
const resultItem = result.item ?? result;
const resultValue = resultItem[this.lang] ?? resultItem['formattedAddress'];

this.resultSelected = true;

if (this.allowMultiple === 'true') {
let value = this.storeExistingSelections(result[this.lang]);
let value = this.storeExistingSelections(resultValue);
result.displayText = value;
} else if (result.url) {
result.displayText = result[this.lang];
window.location = result.url;
} else if (resultItem.url) {
result.displayText = resultValue;
window.location = resultItem.url;
} else {
result.displayText = result[this.lang];
result.displayText = resultValue;
}
this.onSelect(result).then(() => (this.settingResult = false));

Expand Down
3 changes: 2 additions & 1 deletion src/components/autosuggest/example-autosuggest-country.njk
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"resultsTitleId": "country-of-birth-suggestions",
"autosuggestData": "/examples/data/country-of-birth.json",
"noResults": "No suggestions found. You can enter your own answer",
"typeMore": "Continue entering to get suggestions"
"typeMore": "Continue entering to get suggestions",
"resultsThreshold": 0.2
})
}}
</div>
Expand Down
9 changes: 7 additions & 2 deletions src/components/autosuggest/fuse-config.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import Fuse from 'fuse.js';

export default function runFuse(query, data, searchFields) {
export default function runFuse(query, data, searchFields, threshold, distance) {
const options = {
shouldSort: true,
threshold: 0.2,
threshold: threshold,
distance: distance,
keys: [
{
name: searchFields,
weight: 0.9,
},
{
name: 'formattedAddress',
weight: 0.9,
},
{
name: 'tags',
weight: 0.1,
Expand Down
2 changes: 1 addition & 1 deletion src/js/analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default function initAnalytics() {
document.body.addEventListener('click', ({ target }) => {
if (target.getAttribute('data-ga') === 'click') {
return trackElement(target, 'click');
} else if (target.parentElement.getAttribute('data-ga') === 'click') {
} else if (target.parentElement?.getAttribute('data-ga') === 'click') {
return trackElement(target.parentElement, 'click');
}
});
Expand Down
Loading

0 comments on commit 621bdf3

Please sign in to comment.