diff --git a/examples/nuxt-app/test/features/landingpage/custom-collection.feature b/examples/nuxt-app/test/features/landingpage/custom-collection.feature index 16b9334f40..cfae917ec1 100644 --- a/examples/nuxt-app/test/features/landingpage/custom-collection.feature +++ b/examples/nuxt-app/test/features/landingpage/custom-collection.feature @@ -129,3 +129,48 @@ Feature: Custom Collection When I visit the page "/filter-only" Then the custom collection component results count should be hidden + + @mockserver + Example: Autocomplete suggestions are disabled by default + Given the page endpoint for path "/custom-collection-suggestions" returns fixture "/landingpage/custom-collection/page" with status 200 + And the search network request is stubbed with fixture "/landingpage/custom-collection/response" and status 200 + + When I visit the page "/custom-collection-suggestions" + Then I type "The" into the custom collection input + And the search suggestions should not be displayed + + @mockserver + Example: Autocomplete suggestions can be enabled + Given I load the page fixture with "/landingpage/custom-collection/page" + And the search autocomplete request is stubbed with "/landingpage/custom-collection/response-suggestions" fixture + And the custom collection config has "suggestions.enabled" set to "true" + And the search network request is stubbed with fixture "/landingpage/custom-collection/response" and status 200 + Then the page endpoint for path "/custom-collection-suggestions" returns the loaded fixture + + When I visit the page "/custom-collection-suggestions" + Then I type "gover" into the custom collection input + Then the search autocomplete request should be called with the "/landingpage/custom-collection/request-suggestions" fixture + And the search suggestions displayed should include + | govern | + | government | + | government agency | + + @mockserver + Example: Autocomplete minimum characters can be customised + Given I load the page fixture with "/landingpage/custom-collection/page" + And the search autocomplete request is stubbed with "/landingpage/custom-collection/response-suggestions" fixture + And the custom collection config has "suggestions.enabled" set to "true" + And the custom collection config has "suggestions.minCharacters" set to "5" + And the search network request is stubbed with fixture "/landingpage/custom-collection/response" and status 200 + Then the page endpoint for path "/custom-collection-suggestions" returns the loaded fixture + + When I visit the page "/custom-collection-suggestions" + Then I type "gov" into the custom collection input + Then the search suggestions should not be displayed + + When I type "er" into the custom collection input + Then the search autocomplete request should be called with the "/landingpage/custom-collection/request-suggestions" fixture + And the search suggestions displayed should include + | govern | + | government | + | government agency | diff --git a/examples/nuxt-app/test/features/search-listing/suggestions.feature b/examples/nuxt-app/test/features/search-listing/suggestions.feature index 7bc0933a28..fa6f3fb6b1 100644 --- a/examples/nuxt-app/test/features/search-listing/suggestions.feature +++ b/examples/nuxt-app/test/features/search-listing/suggestions.feature @@ -7,7 +7,18 @@ Feature: Search listing - Suggestions And I am using a "macbook-16" device @mockserver - Example: Displays autocomplete suggestions + Example: Autocomplete suggestions are disabled by default + Given the page endpoint for path "/no-suggestions" returns fixture "/search-listing/suggestions/page-no-suggestions" with status 200 + And the search network request is stubbed with fixture "/search-listing/suggestions/search-response" and status 200 + + When I visit the page "/no-suggestions" + Then the search listing page should have 2 results + + When I type "The" into the search input + Then the search suggestions should not be displayed + + @mockserver + Example: Autocomplete suggestions can be enabled Given the page endpoint for path "/suggestions" returns fixture "/search-listing/suggestions/page-suggestions" with status 200 And the search network request is stubbed with fixture "/search-listing/suggestions/search-response" and status 200 And the search autocomplete request is stubbed with "/search-listing/suggestions/response" fixture @@ -32,19 +43,21 @@ Feature: Search listing - Suggestions And the search autocomplete request is stubbed with "/search-listing/suggestions/response" fixture When I visit the page "/suggestions-override" - And I type "The" into the search input + And I type "There" into the search input Then the search autocomplete request should be called with the "/search-listing/suggestions/request-override" fixture @mockserver - Example: Autocomplete suggestions can be disabled - Given the page endpoint for path "/no-suggestions" returns fixture "/search-listing/suggestions/page-no-suggestions" with status 200 + Example: Autocomplete minimum characters can be customised + Given the page endpoint for path "/suggestions-characters" returns fixture "/search-listing/suggestions/page-suggestions-override" with status 200 And the search network request is stubbed with fixture "/search-listing/suggestions/search-response" and status 200 + And the search autocomplete request is stubbed with "/search-listing/suggestions/response" fixture - When I visit the page "/no-suggestions" - Then the search listing page should have 2 results + When I visit the page "/suggestions-characters" + Then I type "The" into the search input + And the search suggestions should not be displayed - When I type "The" into the search input - Then the search suggestions should not be displayed + When I type "re" into the search input + Then the search suggestions should be displayed @mockserver Example: Search bar max input length diff --git a/examples/nuxt-app/test/fixtures/landingpage/custom-collection/request-suggestions.json b/examples/nuxt-app/test/fixtures/landingpage/custom-collection/request-suggestions.json new file mode 100644 index 0000000000..67096fdab3 --- /dev/null +++ b/examples/nuxt-app/test/fixtures/landingpage/custom-collection/request-suggestions.json @@ -0,0 +1,11 @@ +{ + "query": "gover", + "types": { + "documents": { + "fields": [ + "title" + ] + } + }, + "size": 8 +} diff --git a/examples/nuxt-app/test/fixtures/landingpage/custom-collection/response-suggestions.json b/examples/nuxt-app/test/fixtures/landingpage/custom-collection/response-suggestions.json new file mode 100644 index 0000000000..8567242e47 --- /dev/null +++ b/examples/nuxt-app/test/fixtures/landingpage/custom-collection/response-suggestions.json @@ -0,0 +1,18 @@ +{ + "results": { + "documents": [ + { + "suggestion": "govern" + }, + { + "suggestion": "government" + }, + { + "suggestion": "government agency" + } + ] + }, + "meta": { + "request_id": "9b60a1b5a0ec63cc9b61f39236649a04" + } +} diff --git a/examples/nuxt-app/test/fixtures/search-listing/suggestions/page-no-suggestions.json b/examples/nuxt-app/test/fixtures/search-listing/suggestions/page-no-suggestions.json index 8427a6a120..279e9557c6 100644 --- a/examples/nuxt-app/test/fixtures/search-listing/suggestions/page-no-suggestions.json +++ b/examples/nuxt-app/test/fixtures/search-listing/suggestions/page-no-suggestions.json @@ -9,10 +9,7 @@ "config": { "searchListingConfig": { "index": "suggestion_index", - "resultsPerPage": 10, - "suggestions": { - "enabled": false - } + "resultsPerPage": 10 }, "queryConfig": { "multi_match": { diff --git a/examples/nuxt-app/test/fixtures/search-listing/suggestions/page-suggestions-override.json b/examples/nuxt-app/test/fixtures/search-listing/suggestions/page-suggestions-override.json index 20351c3c93..4b0de1e98f 100644 --- a/examples/nuxt-app/test/fixtures/search-listing/suggestions/page-suggestions-override.json +++ b/examples/nuxt-app/test/fixtures/search-listing/suggestions/page-suggestions-override.json @@ -12,7 +12,8 @@ "resultsPerPage": 10, "suggestions": { "enabled": true, - "key": "suggestion_override_key" + "key": "suggestion_override_key", + "minCharacters": 5 } }, "queryConfig": { diff --git a/examples/nuxt-app/test/fixtures/search-listing/suggestions/page-suggestions.json b/examples/nuxt-app/test/fixtures/search-listing/suggestions/page-suggestions.json index 279e9557c6..892e031fa9 100644 --- a/examples/nuxt-app/test/fixtures/search-listing/suggestions/page-suggestions.json +++ b/examples/nuxt-app/test/fixtures/search-listing/suggestions/page-suggestions.json @@ -9,7 +9,10 @@ "config": { "searchListingConfig": { "index": "suggestion_index", - "resultsPerPage": 10 + "resultsPerPage": 10, + "suggestions": { + "enabled": true + } }, "queryConfig": { "multi_match": { diff --git a/examples/nuxt-app/test/fixtures/search-listing/suggestions/request-override.json b/examples/nuxt-app/test/fixtures/search-listing/suggestions/request-override.json index 846fbd529e..7f8e6631ce 100644 --- a/examples/nuxt-app/test/fixtures/search-listing/suggestions/request-override.json +++ b/examples/nuxt-app/test/fixtures/search-listing/suggestions/request-override.json @@ -1,5 +1,5 @@ { - "query": "The", + "query": "There", "types": { "documents": { "fields": [ diff --git a/packages/ripple-test-utils/step_definitions/components/custom-collection.ts b/packages/ripple-test-utils/step_definitions/components/custom-collection.ts index 5e5aef64ae..95007f2326 100644 --- a/packages/ripple-test-utils/step_definitions/components/custom-collection.ts +++ b/packages/ripple-test-utils/step_definitions/components/custom-collection.ts @@ -15,6 +15,10 @@ Then( } ) +When(`I type {string} into the custom collection input`, (inputStr: string) => { + cy.get(`[id="custom-collection-search-bar"]`).type(`${inputStr}`) +}) + Then(`the custom collection component results count should be hidden`, () => { cy.get(`[data-component-type="search-listing-result-count"]`).should( 'not.exist' @@ -124,8 +128,9 @@ When(`I toggle the content collection filters`, () => { Then( 'the custom collection config has {string} set to {string}', - (key: string, value: string | boolean) => { + (key: string, value: string | boolean | number) => { cy.get('@pageFixture').then((response) => { + if (!isNaN(Number(value))) value = Number(value) if (value === 'true') value = true if (value === 'false') value = false set(response, `bodyComponents[0].props.searchListingConfig.${key}`, value) diff --git a/packages/ripple-test-utils/step_definitions/content-types/listing.ts b/packages/ripple-test-utils/step_definitions/content-types/listing.ts index 5345e354b2..67c7ad9e0e 100644 --- a/packages/ripple-test-utils/step_definitions/content-types/listing.ts +++ b/packages/ripple-test-utils/step_definitions/content-types/listing.ts @@ -507,6 +507,10 @@ When('I click the search suggestion labelled {string}', (label: string) => { .click() }) +Then('the search suggestions should be displayed', () => { + cy.get('#tide-search-bar__menu').should('exist') +}) + Then('the search suggestions should not be displayed', () => { cy.get('#tide-search-bar__menu').should('not.exist') }) diff --git a/packages/ripple-tide-search/components/TideSearchListingPage.vue b/packages/ripple-tide-search/components/TideSearchListingPage.vue index 9c43c28e1f..892708076a 100644 --- a/packages/ripple-tide-search/components/TideSearchListingPage.vue +++ b/packages/ripple-tide-search/components/TideSearchListingPage.vue @@ -30,8 +30,6 @@ interface Props { id?: string title: string introText?: string - autocompleteQuery?: boolean - autocompleteMinimumCharacters?: number searchListingConfig?: TideSearchListingConfig['searchListingConfig'] sortOptions?: TideSearchListingConfig['sortOptions'] customQueryConfig?: TideSearchListingConfig['customQueryConfig'] @@ -51,8 +49,6 @@ const props = withDefaults(defineProps(), { id: 'tide-search-listing', title: 'Search', introText: '', - autocompleteQuery: true, - autocompleteMinimumCharacters: 3, globalFilters: () => [], userFilters: () => [], customQueryConfig: undefined, @@ -280,11 +276,11 @@ const handleUpdateSearchTerm = (term: string) => { } const getDebouncedSuggestions = useDebounceFn((term: string) => { - if ( - props.autocompleteQuery && - props.searchListingConfig?.suggestions?.enabled !== false - ) { - if (term?.length >= props.autocompleteMinimumCharacters) { + if (props.searchListingConfig?.suggestions?.enabled) { + const minCharacters = + props.searchListingConfig?.suggestions?.minCharacters || 3 + + if (term?.length >= minCharacters) { getSuggestions() } else if (suggestions.value?.length) { clearSuggestions() diff --git a/packages/ripple-tide-search/components/global/TideCustomCollection.vue b/packages/ripple-tide-search/components/global/TideCustomCollection.vue index b2e85ad3cd..dfd79182db 100644 --- a/packages/ripple-tide-search/components/global/TideCustomCollection.vue +++ b/packages/ripple-tide-search/components/global/TideCustomCollection.vue @@ -21,7 +21,6 @@ interface Props { id: string title?: string introText?: string - autocompleteQuery?: boolean searchListingConfig?: TideSearchListingConfig['searchListingConfig'] sortOptions?: TideSearchListingConfig['sortOptions'] customQueryConfig?: TideSearchListingConfig['customQueryConfig'] @@ -42,7 +41,6 @@ const props = withDefaults(defineProps(), { title: 'Search', introText: '', index: undefined, - autocompleteQuery: false, globalFilters: () => [], userFilters: () => [], customQueryConfig: undefined, @@ -189,6 +187,8 @@ const { isBusy, searchError, getSuggestions, + clearSuggestions, + suggestions, searchTerm, results, filterForm, @@ -391,15 +391,19 @@ const handleFilterReset = (event: rplEventPayload) => { const handleUpdateSearchTerm = (term: string) => { searchTerm.value.q = term - getDebouncedSuggestions() + getDebouncedSuggestions(term) } -const getDebouncedSuggestions = useDebounceFn(() => { - if ( - props.autocompleteQuery && - props.searchListingConfig?.suggestions?.enabled !== false - ) { - getSuggestions() +const getDebouncedSuggestions = useDebounceFn((term: string) => { + if (props.searchListingConfig?.suggestions?.enabled) { + const minCharacters = + props.searchListingConfig?.suggestions?.minCharacters || 3 + + if (term?.length >= minCharacters) { + getSuggestions() + } else if (suggestions.value?.length) { + clearSuggestions() + } } }, 300) @@ -584,6 +588,7 @@ const locationOrGeolocation = computed(() => { :input-label="searchListingConfig?.labels?.submit" :inputValue="searchTerm" :placeholder="searchListingConfig?.labels?.placeholder" + :suggestions="suggestions" :global-events="false" :handle-submit="handleSearchSubmit" :handle-update="handleUpdateSearch" @@ -595,6 +600,7 @@ const locationOrGeolocation = computed(() => { :input-label="searchListingConfig.labels?.submit" :inputValue="searchTerm.q" :placeholder="searchListingConfig.labels?.placeholder" + :suggestions="suggestions" :global-events="false" :maxlength="128" @submit="handleSearchSubmit" diff --git a/packages/ripple-tide-search/types.ts b/packages/ripple-tide-search/types.ts index 0729dd62f3..6b4b953d88 100644 --- a/packages/ripple-tide-search/types.ts +++ b/packages/ripple-tide-search/types.ts @@ -262,8 +262,9 @@ export type TideSearchListingConfig = { * @description options for utilizing the auto suggestions */ suggestions: { - key: string + key?: string enabled: boolean + minCharacters?: number } /** * @description The theme to use for the display of form section and fields