diff --git a/packages/algoliasearch-helper/src/algoliasearch.helper.js b/packages/algoliasearch-helper/src/algoliasearch.helper.js index 9adb88fc89..a782ec57ff 100644 --- a/packages/algoliasearch-helper/src/algoliasearch.helper.js +++ b/packages/algoliasearch-helper/src/algoliasearch.helper.js @@ -322,21 +322,6 @@ AlgoliaSearchHelper.prototype.searchForFacetValues = function ( maxFacetHits, userState ) { - var clientHasSFFV = - typeof this.client.searchForFacetValues === 'function' && - // v5 has a wrong sffv signature - typeof this.client.searchForFacets !== 'function'; - var clientHasInitIndex = typeof this.client.initIndex === 'function'; - if ( - !clientHasSFFV && - !clientHasInitIndex && - typeof this.client.search !== 'function' - ) { - throw new Error( - 'search for facet values (searchable) was called, but this client does not have a function client.searchForFacetValues or client.initIndex(index).searchForFacetValues' - ); - } - var state = this.state.setQueryParameters(userState || {}); var isDisjunctive = state.isDisjunctiveFacet(facet); var algoliaQuery = requestBuilder.getSearchForFacetQuery( @@ -349,34 +334,15 @@ AlgoliaSearchHelper.prototype.searchForFacetValues = function ( this._currentNbQueries++; // eslint-disable-next-line consistent-this var self = this; - var searchForFacetValuesPromise; - // newer algoliasearch ^3.27.1 - ~4.0.0 - if (clientHasSFFV) { - searchForFacetValuesPromise = this.client.searchForFacetValues([ - { indexName: state.index, params: algoliaQuery }, - ]); - // algoliasearch < 3.27.1 - } else if (clientHasInitIndex) { - searchForFacetValuesPromise = this.client - .initIndex(state.index) - .searchForFacetValues(algoliaQuery); - // algoliasearch ~5.0.0 - } else { - // @MAJOR only use client.search - delete algoliaQuery.facetName; - searchForFacetValuesPromise = this.client - .search([ - { - type: 'facet', - facet: facet, - indexName: state.index, - params: algoliaQuery, - }, - ]) - .then(function processResponse(response) { - return response.results[0]; - }); - } + + var searchForFacetValuesPromise = this.client.search([ + { + type: 'facet', + facet: facet, + indexName: state.index, + params: algoliaQuery, + }, + ]); this.emit('searchForFacetValues', { state: state, @@ -389,16 +355,16 @@ AlgoliaSearchHelper.prototype.searchForFacetValues = function ( self._currentNbQueries--; if (self._currentNbQueries === 0) self.emit('searchQueueEmpty'); - content = Array.isArray(content) ? content[0] : content; + var result = content.results[0]; - content.facetHits.forEach(function (f) { + result.facetHits.forEach(function (f) { f.escapedValue = escapeFacetValue(f.value); f.isRefined = isDisjunctive ? state.isDisjunctiveFacetRefined(facet, f.escapedValue) : state.isFacetRefined(facet, f.escapedValue); }); - return content; + return result; }, function (e) { self._currentNbQueries--; diff --git a/packages/algoliasearch-helper/src/requestBuilder.js b/packages/algoliasearch-helper/src/requestBuilder.js index ba28640454..7938804f47 100644 --- a/packages/algoliasearch-helper/src/requestBuilder.js +++ b/packages/algoliasearch-helper/src/requestBuilder.js @@ -434,7 +434,6 @@ var requestBuilder = { : state; var searchForFacetSearchParameters = { facetQuery: query, - facetName: facetName, }; if (typeof maxFacetHits === 'number') { searchForFacetSearchParameters.maxFacetHits = maxFacetHits; diff --git a/packages/algoliasearch-helper/test/spec/algoliasearch.helper/events.js b/packages/algoliasearch-helper/test/spec/algoliasearch.helper/events.js index db8eada81a..8712e0ae56 100644 --- a/packages/algoliasearch-helper/test/spec/algoliasearch.helper/events.js +++ b/packages/algoliasearch-helper/test/spec/algoliasearch.helper/events.js @@ -7,9 +7,6 @@ function makeFakeClient() { search: jest.fn(function () { return new Promise(function () {}); }), - searchForFacetValues: jest.fn(function () { - return new Promise(function () {}); - }), }; } @@ -297,7 +294,7 @@ test( helper.on('searchForFacetValues', searchedForFacetValues); expect(searchedForFacetValues).toHaveBeenCalledTimes(0); - expect(fakeClient.searchForFacetValues).toHaveBeenCalledTimes(0); + expect(fakeClient.search).toHaveBeenCalledTimes(0); helper.searchForFacetValues('city', 'NYC'); expect(searchedForFacetValues).toHaveBeenCalledTimes(1); @@ -306,7 +303,7 @@ test( facet: 'city', query: 'NYC', }); - expect(fakeClient.searchForFacetValues).toHaveBeenCalledTimes(1); + expect(fakeClient.search).toHaveBeenCalledTimes(1); } ); diff --git a/packages/algoliasearch-helper/test/spec/algoliasearch.helper/pendingSearch.js b/packages/algoliasearch-helper/test/spec/algoliasearch.helper/pendingSearch.js index 00018aa06a..d4ed0f265d 100644 --- a/packages/algoliasearch-helper/test/spec/algoliasearch.helper/pendingSearch.js +++ b/packages/algoliasearch-helper/test/spec/algoliasearch.helper/pendingSearch.js @@ -1,7 +1,6 @@ 'use strict'; var algoliasearch = require('algoliasearch'); -var isV5 = (algoliasearch.apiClientVersion || '')[0] === '5'; algoliasearch = algoliasearch.algoliasearch || algoliasearch; var algoliasearchHelper = require('../../../index'); @@ -72,85 +71,45 @@ test('When searchOnce with promises, hasPendingRequests is true', function (done triggerCb(); }); -if (!isV5) { - test('When searchForFacetValues, hasPendingRequests is true (v3, v4)', function (done) { - var client = algoliasearch('dsf', 'dsfdf'); +test('When searchForFacetValues, hasPendingRequests is true', function (done) { + var client = algoliasearch('dsf', 'dsfdf'); - let triggerCb; - client.searchForFacetValues = function () { - return new Promise(function (resolve) { - triggerCb = function () { - resolve([ + let triggerCb; + client.search = function () { + return new Promise(function (resolve) { + triggerCb = function () { + resolve({ + results: [ { exhaustiveFacetsCount: true, facetHits: [], processingTimeMS: 3, }, - ]); - }; - }); - }; - - var helper = algoliasearchHelper(client, 'test_hotels-node'); - var countNoMoreSearch = 0; - helper.on('searchQueueEmpty', function () { - countNoMoreSearch += 1; - }); - - expect(helper.hasPendingRequests()).toBe(false); - - helper.searchForFacetValues('').then(function () { - expect(helper.hasPendingRequests()).toBe(false); - expect(countNoMoreSearch).toBe(1); - done(); + ], + }); + }; }); + }; - expect(helper.hasPendingRequests()).toBe(true); - expect(countNoMoreSearch).toBe(0); - - triggerCb(); + var helper = algoliasearchHelper(client, 'test_hotels-node'); + var countNoMoreSearch = 0; + helper.on('searchQueueEmpty', function () { + countNoMoreSearch += 1; }); -} else { - test('When searchForFacetValues, hasPendingRequests is true (v5)', function (done) { - var client = algoliasearch('dsf', 'dsfdf'); - - let triggerCb; - client.search = function () { - return new Promise(function (resolve) { - triggerCb = function () { - resolve({ - results: [ - { - exhaustiveFacetsCount: true, - facetHits: [], - processingTimeMS: 3, - }, - ], - }); - }; - }); - }; - var helper = algoliasearchHelper(client, 'test_hotels-node'); - var countNoMoreSearch = 0; - helper.on('searchQueueEmpty', function () { - countNoMoreSearch += 1; - }); + expect(helper.hasPendingRequests()).toBe(false); + helper.searchForFacetValues('').then(function () { expect(helper.hasPendingRequests()).toBe(false); + expect(countNoMoreSearch).toBe(1); + done(); + }); - helper.searchForFacetValues('').then(function () { - expect(helper.hasPendingRequests()).toBe(false); - expect(countNoMoreSearch).toBe(1); - done(); - }); - - expect(helper.hasPendingRequests()).toBe(true); - expect(countNoMoreSearch).toBe(0); + expect(helper.hasPendingRequests()).toBe(true); + expect(countNoMoreSearch).toBe(0); - triggerCb(); - }); -} + triggerCb(); +}); test('When helper.search(), hasPendingRequests is true', function (done) { var testData = require('../../datasets/SearchParameters/search.dataset')(); diff --git a/packages/algoliasearch-helper/test/spec/algoliasearch.helper/searchForFacetValues.js b/packages/algoliasearch-helper/test/spec/algoliasearch.helper/searchForFacetValues.js index 6606e6d0e0..7e4d1b3e07 100644 --- a/packages/algoliasearch-helper/test/spec/algoliasearch.helper/searchForFacetValues.js +++ b/packages/algoliasearch-helper/test/spec/algoliasearch.helper/searchForFacetValues.js @@ -10,77 +10,36 @@ function makeFakeSearchForFacetValuesResponse() { }; } -test('searchForFacetValues calls the client method over the index method', function () { - var clientSearchForFacetValues = jest.fn(function () { - return Promise.resolve([makeFakeSearchForFacetValuesResponse()]); - }); - - var indexSearchForFacetValues = jest.fn(function () { - return Promise.resolve(makeFakeSearchForFacetValuesResponse()); - }); - - var fakeClient = { - searchForFacetValues: clientSearchForFacetValues, - initIndex: function () { - return { - searchForFacetValues: indexSearchForFacetValues, - }; - }, - }; - - var helper = algoliasearchHelper(fakeClient, 'index'); - - return helper.searchForFacetValues('facet', 'query', 1).then(function () { - expect(clientSearchForFacetValues).toHaveBeenCalledTimes(1); - expect(indexSearchForFacetValues).toHaveBeenCalledTimes(0); - }); -}); - -test('searchForFacetValues calls the index method if no client method', function () { - var indexSearchForFacetValues = jest.fn(function () { - return Promise.resolve(makeFakeSearchForFacetValuesResponse()); - }); - +test('searchForFacetValues calls client.search if client.searchForFacets exists', function () { var fakeClient = { initIndex: function () { return { - searchForFacetValues: indexSearchForFacetValues, + searchForFacetValues: jest.fn(function () {}), }; }, - }; - - var helper = algoliasearchHelper(fakeClient, 'index'); - - return helper.searchForFacetValues('facet', 'query', 1).then(function () { - expect(indexSearchForFacetValues).toHaveBeenCalledTimes(1); - }); -}); - -test('searchForFacetValues calls client.search if client.searchForFacets exists', function () { - var clientSearch = jest.fn(function () { - return Promise.resolve({ - results: [makeFakeSearchForFacetValuesResponse()], - }); - }); - - var fakeClient = { searchForFacets: jest.fn(), searchForFacetValues: jest.fn(), - search: clientSearch, + search: jest.fn(function () { + return Promise.resolve({ + results: [makeFakeSearchForFacetValuesResponse()], + }); + }), }; var helper = algoliasearchHelper(fakeClient, 'index'); return helper.searchForFacetValues('facet', 'query', 1).then(function () { - expect(clientSearch).toHaveBeenCalledTimes(1); + expect(fakeClient.search).toHaveBeenCalledTimes(1); }); }); test('searchForFacetValues resolve with the correct response from client', function () { var fakeClient = { addAlgoliaAgent: function () {}, - searchForFacetValues: function () { - return Promise.resolve([makeFakeSearchForFacetValuesResponse()]); + search: function () { + return Promise.resolve({ + results: [makeFakeSearchForFacetValuesResponse()], + }); }, }; @@ -95,158 +54,14 @@ test('searchForFacetValues resolve with the correct response from client', funct }); }); -test('searchForFacetValues resolve with the correct response from initIndex', function () { +test('searchForFacetValues should search for facetValues with the current state', function () { var fakeClient = { addAlgoliaAgent: function () {}, - initIndex: function () { - return { - searchForFacetValues: function () { - return Promise.resolve(makeFakeSearchForFacetValuesResponse()); - }, - }; - }, - }; - - var helper = algoliasearchHelper(fakeClient, 'index'); - - return helper - .searchForFacetValues('facet', 'query', 1) - .then(function (content) { - expect(content.exhaustiveFacetsCount).toBe(true); - expect(content.facetHits.length).toBe(0); - expect(content.processingTimeMS).toBe(3); - }); -}); - -test('index.searchForFacetValues should search for facetValues with the current state', function () { - var indexSearchForFacetValues = jest.fn(function () { - return Promise.resolve(makeFakeSearchForFacetValuesResponse()); - }); - - var fakeClient = { - initIndex: function () { - return { - searchForFacetValues: indexSearchForFacetValues, - }; - }, - }; - - var helper = algoliasearchHelper(fakeClient, 'index', { - highlightPreTag: 'HIGHLIGHT>', - highlightPostTag: ''); - expect(lastArguments.highlightPostTag).toBe('', - highlightPostTag: '', - highlightPostTag: ''); - expect(lastArguments.params.highlightPostTag).toBe('', - highlightPostTag: ''); expect(lastArguments.params.highlightPostTag).toBe('; -// v5 only has the `searchForFacetValues` method in the `search` client, not in `lite`. -// We need to check both clients to get the correct type. -// (this is not actually used in the codebase, but it's here for completeness) -type SearchForFacetValuesV5 = ClientSearchV5 | ClientFullV5 extends { - searchForFacetValues: unknown; -} - ? - | ClientSearchV5['searchForFacetValues'] - | ClientFullV5['searchForFacetValues'] - : never; - export interface SearchClient { search: ( - requests: Array<{ indexName: string; params: SearchOptions }> + requests: Array< + | { + type?: 'default'; + indexName: string; + params: SearchOptions; + } + | { + type: 'facet'; + indexName: string; + facet: string; + params: SearchOptions & { + maxFacetHits?: number; + facetQuery?: string; + }; + } + > ) => Promise>; getRecommendations?: ( requests: RecommendOptions[] ) => Promise>; - searchForFacetValues?: DefaultSearchClient extends { - searchForFacetValues: unknown; - } - ? DefaultSearchClient['searchForFacetValues'] - : SearchForFacetValuesV5; - initIndex?: DefaultSearchClient extends { initIndex: unknown } - ? DefaultSearchClient['initIndex'] - : never; addAlgoliaAgent?: DefaultSearchClient['addAlgoliaAgent']; } diff --git a/packages/instantsearch-core/src/connectors/__tests__/connectRefinementList.test.ts b/packages/instantsearch-core/src/connectors/__tests__/connectRefinementList.test.ts index a4630eb9ef..8c442e5e16 100644 --- a/packages/instantsearch-core/src/connectors/__tests__/connectRefinementList.test.ts +++ b/packages/instantsearch-core/src/connectors/__tests__/connectRefinementList.test.ts @@ -1,9 +1,11 @@ import { createSingleSearchResponse, createSearchClient, + createSFFVResponse, + createMultiSearchResponse, } from '@instantsearch/mocks'; import { wait } from '@instantsearch/testutils/wait'; -import jsHelper, { +import algoliasearchHelper, { SearchResults, SearchParameters, } from 'algoliasearch-helper'; @@ -181,7 +183,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- showMoreLimit: 30, }); - const helper = jsHelper( + const helper = algoliasearchHelper( createSearchClient(), '', widget.getWidgetSearchParameters(new SearchParameters({}), { @@ -266,7 +268,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- showMoreLimit: 30, }); - const helper = jsHelper( + const helper = algoliasearchHelper( createSearchClient(), '', widget.getWidgetSearchParameters(new SearchParameters({}), { @@ -374,7 +376,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- // test if widget is not rendered yet at this point expect(rendering).not.toHaveBeenCalled(); - const helper = jsHelper(createSearchClient(), '', config); + const helper = algoliasearchHelper(createSearchClient(), '', config); helper.search = jest.fn(); widget.init!( @@ -428,7 +430,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- limit: 9, }); - const helper = jsHelper(createSearchClient(), ''); + const helper = algoliasearchHelper(createSearchClient(), ''); widget.render!( createRenderOptions({ @@ -462,7 +464,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- })), }); - const helper = jsHelper( + const helper = algoliasearchHelper( createSearchClient(), '', widget.getWidgetSearchParameters(new SearchParameters({}), { @@ -530,7 +532,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- transformItems, }); - const helper = jsHelper(createSearchClient(), ''); + const helper = algoliasearchHelper(createSearchClient(), ''); const results = new SearchResults(helper.state, [ createSingleSearchResponse(), ]); @@ -557,7 +559,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- attribute: 'category', }); - const helper = jsHelper( + const helper = algoliasearchHelper( createSearchClient(), '', widget.getWidgetSearchParameters(new SearchParameters({}), { @@ -612,7 +614,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- operator: 'and', }); - const helper = jsHelper( + const helper = algoliasearchHelper( createSearchClient(), '', widget.getWidgetSearchParameters(new SearchParameters({}), { @@ -668,7 +670,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- showMoreLimit: 10, }); - const helper = jsHelper( + const helper = algoliasearchHelper( createSearchClient(), '', widget.getWidgetSearchParameters(new SearchParameters({}), { @@ -723,7 +725,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- limit: 1, }); - const helper = jsHelper( + const helper = algoliasearchHelper( createSearchClient(), '', widget.getWidgetSearchParameters(new SearchParameters({}), { @@ -784,7 +786,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- showMoreLimit: 10, }); - const helper = jsHelper( + const helper = algoliasearchHelper( createSearchClient(), '', widget.getWidgetSearchParameters(new SearchParameters({}), { @@ -845,7 +847,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- showMoreLimit: 10, }); - const helper = jsHelper( + const helper = algoliasearchHelper( createSearchClient(), '', widget.getWidgetSearchParameters(new SearchParameters({}), { @@ -909,7 +911,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- showMoreLimit: 3, }); - const helper = jsHelper( + const helper = algoliasearchHelper( createSearchClient(), '', widget.getWidgetSearchParameters(new SearchParameters({}), { @@ -1014,19 +1016,14 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- showMoreLimit, }); - const helper = jsHelper( - createSearchClient(), + const client = createSearchClient(); + const helper = algoliasearchHelper( + client, '', widget.getWidgetSearchParameters(new SearchParameters({}), { uiState: {}, }) ); - helper.search = jest.fn(); - helper.searchForFacetValues = jest.fn().mockReturnValue( - Promise.resolve({ - facetHits: [], - }) - ); widget.init!( createInitOptions({ @@ -1101,12 +1098,21 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- renderingOptions2.searchForItems('query triggering no results'); await wait(0); - expect(helper.searchForFacetValues).toHaveBeenCalledWith( - expect.anything(), - expect.anything(), - limit, - expect.anything() - ); + expect(client.search).toHaveBeenCalledWith([ + { + type: 'facet', + facet: 'category', + indexName: '', + params: { + facetQuery: 'query triggering no results', + facets: ['category'], + highlightPostTag: '__/ais-highlight__', + highlightPreTag: '__ais-highlight__', + maxFacetHits: limit, + maxValuesPerFacet: showMoreLimit, + }, + }, + ]); expect(rendering).toHaveBeenCalledTimes(3); const renderingOptions3 = rendering.mock.calls[2][0]; @@ -1208,12 +1214,21 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- }); renderingOptions5.searchForItems('new search'); - expect(helper.searchForFacetValues).toHaveBeenCalledWith( - expect.anything(), - expect.anything(), - showMoreLimit, - expect.anything() - ); + expect(client.search).toHaveBeenCalledWith([ + { + type: 'facet', + facet: 'category', + indexName: '', + params: { + facetQuery: 'new search', + facets: ['category'], + highlightPostTag: '__/ais-highlight__', + highlightPreTag: '__ais-highlight__', + maxFacetHits: showMoreLimit, + maxValuesPerFacet: showMoreLimit, + }, + }, + ]); }); it('Toggle show more should be enabled when refinement list is expanded and number of facet is above limit and below showMoreLimit', () => { @@ -1225,7 +1240,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- showMoreLimit: 3, }); - const helper = jsHelper(createSearchClient(), '', { + const helper = algoliasearchHelper(createSearchClient(), '', { ...widget.getWidgetSearchParameters(new SearchParameters({}), { uiState: {}, }), @@ -1323,7 +1338,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- showMoreLimit: 3, }); - const helper = jsHelper(createSearchClient(), '', { + const helper = algoliasearchHelper(createSearchClient(), '', { ...widget.getWidgetSearchParameters(new SearchParameters({}), { uiState: {}, }), @@ -1417,7 +1432,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- limit: 2, }); - const helper = jsHelper( + const helper = algoliasearchHelper( createSearchClient(), '', widget.getWidgetSearchParameters(new SearchParameters({}), { @@ -1505,7 +1520,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- limit: 2, }); - const helper = jsHelper(createSearchClient(), '', { + const helper = algoliasearchHelper(createSearchClient(), '', { ...widget.getWidgetSearchParameters(new SearchParameters({}), { uiState: {}, }), @@ -1594,31 +1609,9 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- limit: 2, escapeFacetValues: false, }); - - const helper = jsHelper( - createSearchClient({ - // @ts-ignore v5 does not have this method, but it's easier to have it here. In a future version we can replace this method and its usages with search({ type: 'facet }) - searchForFacetValues() { - return Promise.resolve([ - { - exhaustiveFacetsCount: true, - facetHits: [ - { - count: 33, - highlighted: 'Salvador Dali', - value: 'Salvador Dali', - }, - { - count: 9, - highlighted: 'Davidoff', - value: 'Davidoff', - }, - ], - processingTimeMS: 1, - }, - ]); - }, - }), + const client = createMockClient(); + const helper = algoliasearchHelper( + client, '', widget.getWidgetSearchParameters(new SearchParameters({}), { uiState: {}, @@ -1626,11 +1619,6 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- ); helper.search = jest.fn(); - const searchForFacetValuesSpy = jest.spyOn( - helper, - 'searchForFacetValues' - ); - // Simulate the lifecycle widget.init!( createInitOptions({ @@ -1677,16 +1665,21 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- const search = rendering.mock.calls[1][0].searchForItems; search('da'); - const [sffvFacet, sffvQuery, maxNbItems, paramOverride] = - searchForFacetValuesSpy.mock.calls[0]; - - expect(sffvQuery).toBe('da'); - expect(sffvFacet).toBe('category'); - expect(maxNbItems).toBe(2); - expect(paramOverride).toEqual({ - highlightPreTag: '', - highlightPostTag: '', - }); + expect(client.search).toHaveBeenCalledWith([ + { + type: 'facet', + facet: 'category', + indexName: '', + params: { + facetQuery: 'da', + facets: ['category'], + highlightPostTag: '', + highlightPreTag: '', + maxFacetHits: 2, + maxValuesPerFacet: 2, + }, + }, + ]); await wait(0); @@ -1717,29 +1710,14 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- showMoreLimit: 1000, }); - const helper = jsHelper( - createSearchClient({ - // @ts-ignore v5 does not have this method, but it's easier to have it here. In a future version we can replace this method and its usages with search({ type: 'facet }) - searchForFacetValues() { - return Promise.resolve([ - { - exhaustiveFacetsCount: true, - facetHits: [], - processingTimeMS: 1, - }, - ]); - }, - }), + const client = createMockClient(); + const helper = algoliasearchHelper( + client, '', widget.getWidgetSearchParameters(new SearchParameters({}), { uiState: {}, }) ); - helper.search = jest.fn(); - const searchForFacetValuesSpy = jest.spyOn( - helper, - 'searchForFacetValues' - ); widget.init!( createInitOptions({ @@ -1780,9 +1758,11 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- const { searchForItems } = rendering.mock.calls[2][0]; searchForItems('query'); - const maxNbItems = searchForFacetValuesSpy.mock.calls[0][2]; - - expect(maxNbItems).toBe(100); + expect(client.search).toHaveBeenCalledWith([ + expect.objectContaining({ + params: expect.objectContaining({ maxFacetHits: 100 }), + }), + ]); }); it('can search in facet values with transformed items', async () => { @@ -1800,40 +1780,14 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- })), }); - const helper = jsHelper( - createSearchClient({ - // @ts-ignore v5 does not have this method, but it's easier to have it here. In a future version we can replace this method and its usages with search({ type: 'facet }) - searchForFacetValues() { - return Promise.resolve([ - { - exhaustiveFacetsCount: true, - facetHits: [ - { - count: 33, - highlighted: 'will be transformed', - value: 'will be transformed', - }, - { - count: 9, - highlighted: 'will be transformed', - value: 'will be transformed', - }, - ], - processingTimeMS: 1, - }, - ]); - }, - }), + const client = createMockClient(); + const helper = algoliasearchHelper( + client, '', widget.getWidgetSearchParameters(new SearchParameters({}), { uiState: {}, }) ); - helper.search = jest.fn(); - const searchForFacetValuesSpy = jest.spyOn( - helper, - 'searchForFacetValues' - ); // Simulate the lifecycle widget.init!( @@ -1875,16 +1829,21 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- const search = rendering.mock.calls[1][0].searchForItems; search('transfo'); - const [sffvFacet, sffvQuery, maxNbItems, paramOverride] = - searchForFacetValuesSpy.mock.calls[0]; - - expect(sffvQuery).toBe('transfo'); - expect(sffvFacet).toBe('category'); - expect(maxNbItems).toBe(2); - expect(paramOverride).toEqual({ - highlightPreTag: '', - highlightPostTag: '', - }); + expect(client.search).toHaveBeenCalledWith([ + { + type: 'facet', + facet: 'category', + indexName: '', + params: { + facetQuery: 'transfo', + facets: ['category'], + highlightPostTag: '', + highlightPreTag: '', + maxFacetHits: 2, + maxValuesPerFacet: 2, + }, + }, + ]); await wait(0); @@ -1911,44 +1870,15 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- escapeFacetValues: false, }); - const helper = jsHelper( - createSearchClient({ - // @ts-ignore v5 does not have this method, but it's easier to have it here. In a future version we can replace this method and its usages with search({ type: 'facet }) - searchForFacetValues() { - return Promise.resolve([ - { - exhaustiveFacetsCount: true, - facetHits: [ - { - count: 33, - highlighted: 'Salvador Dali', - value: 'Salvador Dali', - }, - { - count: 9, - highlighted: 'Davidoff', - value: 'Davidoff', - }, - ], - processingTimeMS: 1, - }, - ]); - }, + const client = createMockClient(); + const helper = algoliasearchHelper(client, '', { + ...widget.getWidgetSearchParameters(new SearchParameters({}), { + uiState: {}, }), - '', - { - ...widget.getWidgetSearchParameters(new SearchParameters({}), { - uiState: {}, - }), - // Here we simulate that another widget has set some highlight tags - ...TAG_PLACEHOLDER, - } - ); + // Here we simulate that another widget has set some highlight tags + ...TAG_PLACEHOLDER, + }); helper.search = jest.fn(); - const searchForFacetValuesSpy = jest.spyOn( - helper, - 'searchForFacetValues' - ); // Simulate the lifecycle widget.init!( @@ -1990,16 +1920,21 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- const search = rendering.mock.calls[1][0].searchForItems; search('da'); - const [sffvFacet, sffvQuery, maxNbItems, paramOverride] = - searchForFacetValuesSpy.mock.calls[0]; - - expect(sffvQuery).toBe('da'); - expect(sffvFacet).toBe('category'); - expect(maxNbItems).toBe(2); - expect(paramOverride).toEqual({ - highlightPreTag: '', - highlightPostTag: '', - }); + expect(client.search).toHaveBeenCalledWith([ + { + type: 'facet', + facet: 'category', + indexName: '', + params: { + facetQuery: 'da', + facets: ['category'], + highlightPostTag: '', + highlightPreTag: '', + maxFacetHits: 2, + maxValuesPerFacet: 2, + }, + }, + ]); await wait(0); @@ -2030,44 +1965,14 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- escapeFacetValues: true, }); - const helper = jsHelper( - createSearchClient({ - // @ts-ignore v5 does not have this method, but it's easier to have it here. In a future version we can replace this method and its usages with search({ type: 'facet }) - searchForFacetValues() { - return Promise.resolve([ - { - exhaustiveFacetsCount: true, - facetHits: [ - { - count: 33, - highlighted: `Salvador ${TAG_PLACEHOLDER.highlightPreTag}Da${TAG_PLACEHOLDER.highlightPostTag}li`, - value: 'Salvador Dali', - }, - { - count: 9, - highlighted: `${TAG_PLACEHOLDER.highlightPreTag}Da${TAG_PLACEHOLDER.highlightPostTag}vidoff`, - value: 'Davidoff', - }, - ], - processingTimeMS: 1, - }, - ]); - }, + const client = createMockClient(); + const helper = algoliasearchHelper(client, '', { + ...widget.getWidgetSearchParameters(new SearchParameters({}), { + uiState: {}, }), - '', - { - ...widget.getWidgetSearchParameters(new SearchParameters({}), { - uiState: {}, - }), - // Here we simulate that another widget has set some highlight tags - ...TAG_PLACEHOLDER, - } - ); - helper.search = jest.fn(); - const searchForFacetValuesSpy = jest.spyOn( - helper, - 'searchForFacetValues' - ); + // Here we simulate that another widget has set some highlight tags + ...TAG_PLACEHOLDER, + }); // Simulate the lifecycle widget.init!( @@ -2109,13 +2014,20 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- const search = rendering.mock.calls[1][0].searchForItems; search('da'); - const [sffvFacet, sffvQuery, maxNbItems, paramOverride] = - searchForFacetValuesSpy.mock.calls[0]; - - expect(sffvQuery).toBe('da'); - expect(sffvFacet).toBe('category'); - expect(maxNbItems).toBe(2); - expect(paramOverride).toEqual(TAG_PLACEHOLDER); + expect(client.search).toHaveBeenCalledWith([ + { + type: 'facet', + facet: 'category', + indexName: '', + params: { + facetQuery: 'da', + facets: ['category'], + ...TAG_PLACEHOLDER, + maxFacetHits: 2, + maxValuesPerFacet: 2, + }, + }, + ]); await wait(0); @@ -2145,7 +2057,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- const widget = makeWidget({ attribute: 'myFacet', }); - const helper = jsHelper( + const helper = algoliasearchHelper( createSearchClient(), '', widget.getWidgetSearchParameters(new SearchParameters({}), { @@ -2170,7 +2082,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- }); const indexName = 'my-index'; - const helper = jsHelper( + const helper = algoliasearchHelper( createSearchClient(), indexName, widget.getWidgetSearchParameters(new SearchParameters({}), { @@ -2265,7 +2177,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- }); const indexName = 'my-index'; - const helper = jsHelper( + const helper = algoliasearchHelper( createSearchClient(), indexName, widget.getWidgetSearchParameters(new SearchParameters({}), { @@ -2354,7 +2266,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `uiState` empty', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), ''); + const helper = algoliasearchHelper(createSearchClient(), ''); const widget = makeWidget({ attribute: 'brand', }); @@ -2373,7 +2285,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `uiState` with a refinement', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), '', { + const helper = algoliasearchHelper(createSearchClient(), '', { disjunctiveFacets: ['brand'], disjunctiveFacetsRefinements: { brand: ['Apple', 'Microsoft'], @@ -2402,7 +2314,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `uiState` without namespace overridden', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), '', { + const helper = algoliasearchHelper(createSearchClient(), '', { disjunctiveFacets: ['brand'], disjunctiveFacetsRefinements: { brand: ['Apple', 'Microsoft'], @@ -2440,7 +2352,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- const unmountFn = jest.fn(); const createRefinementList = connectRefinementList(renderFn, unmountFn); const refinementListWidget = createRefinementList({ attribute: 'brand' }); - const helper = jsHelper(createSearchClient(), 'indexName', { + const helper = algoliasearchHelper(createSearchClient(), 'indexName', { disjunctiveFacets: ['brand'], disjunctiveFacetsRefinements: { brand: ['Apple', 'Microsoft'], @@ -2476,7 +2388,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- const unmountFn = jest.fn(); const createRefinementList = connectRefinementList(renderFn, unmountFn); const refinementListWidget = createRefinementList({ attribute: 'brand' }); - const helper = jsHelper(createSearchClient(), 'indexName', { + const helper = algoliasearchHelper(createSearchClient(), 'indexName', { disjunctiveFacets: ['brand'], disjunctiveFacetsRefinements: { brand: ['Apple', 'Microsoft'], @@ -2560,7 +2472,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- const unmountFn = jest.fn(); const createRefinementList = connectRefinementList(renderFn, unmountFn); const refinementListWidget = createRefinementList({ attribute: 'brand' }); - const helper = jsHelper(createSearchClient(), 'indexName', { + const helper = algoliasearchHelper(createSearchClient(), 'indexName', { disjunctiveFacets: ['brand'], disjunctiveFacetsRefinements: { brand: ['Apple', 'Microsoft'], @@ -2593,7 +2505,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- it('returns the widget render state with results', () => { const createRefinementList = connectRefinementList(jest.fn(), jest.fn()); const refinementListWidget = createRefinementList({ attribute: 'brand' }); - const helper = jsHelper(createSearchClient(), 'indexName', { + const helper = algoliasearchHelper(createSearchClient(), 'indexName', { disjunctiveFacets: ['brand'], disjunctiveFacetsRefinements: { brand: ['Apple', 'Microsoft'], @@ -2682,7 +2594,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- const refinementListWidget = createRefinementList({ attribute: 'discounts', }); - const helper = jsHelper(createSearchClient(), 'indexName', { + const helper = algoliasearchHelper(createSearchClient(), 'indexName', { disjunctiveFacets: ['discounts'], disjunctiveFacetsRefinements: { discounts: ['\\-10%', '\\-2€'], @@ -2833,7 +2745,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- attribute: 'brand', sortBy, }); - const helper = jsHelper( + const helper = algoliasearchHelper( createSearchClient(), 'indexName', refinementList.getWidgetSearchParameters(new SearchParameters(), { @@ -2885,7 +2797,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `SearchParameters` with default `limit`', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), ''); + const helper = algoliasearchHelper(createSearchClient(), ''); const widget = makeWidget({ attribute: 'brand', }); @@ -2900,7 +2812,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `SearchParameters` with provided `limit`', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), ''); + const helper = algoliasearchHelper(createSearchClient(), ''); const widget = makeWidget({ attribute: 'brand', limit: 5, @@ -2916,7 +2828,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `SearchParameters` with default `showMoreLimit`', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), ''); + const helper = algoliasearchHelper(createSearchClient(), ''); const widget = makeWidget({ attribute: 'brand', showMore: true, @@ -2932,7 +2844,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `SearchParameters` with provided `showMoreLimit`', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), ''); + const helper = algoliasearchHelper(createSearchClient(), ''); const widget = makeWidget({ attribute: 'brand', showMore: true, @@ -2949,7 +2861,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `SearchParameters` with the previous value if higher than `limit`/`showMoreLimit`', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), '', { + const helper = algoliasearchHelper(createSearchClient(), '', { maxValuesPerFacet: 100, }); @@ -2967,7 +2879,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `SearchParameters` with `limit`/`showMoreLimit` if higher than previous value', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), '', { + const helper = algoliasearchHelper(createSearchClient(), '', { maxValuesPerFacet: 100, }); @@ -2988,7 +2900,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `SearchParameters` with the default value', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), ''); + const helper = algoliasearchHelper(createSearchClient(), ''); const widget = makeWidget({ attribute: 'brand', operator: 'and', @@ -3007,7 +2919,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `SearchParameters` with the default value without the previous refinement', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), '', { + const helper = algoliasearchHelper(createSearchClient(), '', { facets: ['brand'], facetsRefinements: { brand: ['Apple', 'Samsung'], @@ -3032,7 +2944,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `SearchParameters` with the value from `uiState`', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), ''); + const helper = algoliasearchHelper(createSearchClient(), ''); const widget = makeWidget({ attribute: 'brand', operator: 'and', @@ -3055,7 +2967,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `SearchParameters` with the value from `uiState` without the previous refinement', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), '', { + const helper = algoliasearchHelper(createSearchClient(), '', { facets: ['brand'], facetsRefinements: { brand: ['Microsoft'], @@ -3085,7 +2997,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- warnCache.current = {}; const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), '', { + const helper = algoliasearchHelper(createSearchClient(), '', { disjunctiveFacets: ['brand'], }); @@ -3106,7 +3018,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `SearchParameters` with the default value', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), ''); + const helper = algoliasearchHelper(createSearchClient(), ''); const widget = makeWidget({ attribute: 'brand', }); @@ -3124,7 +3036,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `SearchParameters` with the default value without the previous refinement', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), '', { + const helper = algoliasearchHelper(createSearchClient(), '', { disjunctiveFacets: ['brand'], disjunctiveFacetsRefinements: { brand: ['Apple', 'Samsung'], @@ -3148,7 +3060,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `SearchParameters` with the value from `uiState`', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), ''); + const helper = algoliasearchHelper(createSearchClient(), ''); const widget = makeWidget({ attribute: 'brand', }); @@ -3170,7 +3082,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('returns the `SearchParameters` with the value from `uiState` without the previous refinement', () => { const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), '', { + const helper = algoliasearchHelper(createSearchClient(), '', { disjunctiveFacets: ['brand'], disjunctiveFacetsRefinements: { brand: ['Microsoft'], @@ -3199,7 +3111,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- warnCache.current = {}; const render = () => {}; const makeWidget = connectRefinementList(render); - const helper = jsHelper(createSearchClient(), '', { + const helper = algoliasearchHelper(createSearchClient(), '', { facets: ['brand'], }); @@ -3217,7 +3129,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- test('warns when attribute is used for hierarchical faceting and does not change `SearchParameters`', () => { warnCache.current = {}; - const helper = jsHelper(createSearchClient(), '', { + const helper = algoliasearchHelper(createSearchClient(), '', { hierarchicalFacets: [{ name: 'brand', attributes: ['brand'] }], }); const widget = connectRefinementList(jest.fn())({ attribute: 'brand' }); @@ -3242,7 +3154,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- attribute: 'category', }); - const helper = jsHelper( + const helper = algoliasearchHelper( createSearchClient(), '', widget.getWidgetSearchParameters(new SearchParameters({}), { @@ -3306,3 +3218,36 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/refinement- }); }); }); + +function createMockClient() { + const client = createSearchClient({ + search: jest.fn((requests) => { + return Promise.resolve( + createMultiSearchResponse( + ...requests.map((request) => + request.type === 'facet' + ? createSFFVResponse({ + facetHits: + request.params.facetQuery === 'nothing' + ? [] + : [ + { + count: 33, + highlighted: `Salvador ${request.params.highlightPreTag}Da${request.params.highlightPostTag}li`, + value: 'Salvador Dali', + }, + { + count: 9, + highlighted: `${request.params.highlightPreTag}Da${request.params.highlightPostTag}vidoff`, + value: 'Davidoff', + }, + ], + }) + : createSingleSearchResponse() + ) + ) + ); + }), + }); + return client; +} diff --git a/packages/instantsearch.js/src/widgets/index/__tests__/index-test.ts b/packages/instantsearch-core/src/widgets/__tests__/index-widget.test.ts similarity index 98% rename from packages/instantsearch.js/src/widgets/index/__tests__/index-test.ts rename to packages/instantsearch-core/src/widgets/__tests__/index-widget.test.ts index 88ba45166c..8fb7b73cb3 100644 --- a/packages/instantsearch.js/src/widgets/index/__tests__/index-test.ts +++ b/packages/instantsearch-core/src/widgets/__tests__/index-widget.test.ts @@ -7,7 +7,7 @@ import { createSingleRecommendResponse, createSingleSearchResponse, } from '@instantsearch/mocks'; -import { wait } from '@instantsearch/testutils'; +import { wait, castToJestMock } from '@instantsearch/testutils'; import algoliasearchHelper, { SearchResults, SearchParameters, @@ -15,24 +15,23 @@ import algoliasearchHelper, { RecommendResults, } from 'algoliasearch-helper'; -import { castToJestMock } from '../../../../../../tests/utils'; -import { createInstantSearch } from '../../../../test/createInstantSearch'; -import { - createWidget, - createIndexInitOptions, - createDisposeOptions, -} from '../../../../test/createWidget'; import { + instantsearch, + index, connectHits, connectPagination, connectRefinementList, connectSearchBox, -} from '../../../connectors'; -import instantsearch from '../../../index.es'; -import { warnCache } from '../../../lib/utils'; -import index from '../index'; +} from '../..'; +import { createInstantSearch } from '../../../test/createInstantSearch'; +import { + createWidget, + createIndexInitOptions, + createDisposeOptions, +} from '../../../test/createWidget'; +import { warnCache } from '../../lib/public'; -import type { Widget } from '../../../types'; +import type { Widget } from '../../types'; import type { PlainSearchParameters } from 'algoliasearch-helper'; describe('index', () => { @@ -972,15 +971,10 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/index-widge it('create URLs with non-namesake helper state', () => { const instance = index({ indexName: 'indexName' }); - const searchBox = virtualSearchBox({}); - const pagination = virtualPagination({}); - - const container = document.createElement('div'); - document.body.append(container); instance.addWidgets([ - searchBox, - pagination, + virtualSearchBox({}), + virtualPagination({}), virtualRefinementList({ attribute: 'doggies' }), ]); @@ -1452,7 +1446,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/index-widge instance.addWidgets([ createSearchBox({ getWidgetSearchParameters(state) { - return state.setQueryParameter('query', 'Apple'); + return state.setQueryParameter('query', 'Global Query'); }, }), createPagination({ @@ -1475,22 +1469,22 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/index-widge highlightPostTag: '', }); - expect(searchClient.searchForFacetValues).toHaveBeenCalledTimes(1); - expect(searchClient.searchForFacetValues).toHaveBeenCalledWith( - expect.arrayContaining([ - { - indexName: 'indexName', - params: expect.objectContaining({ - facetName: 'brand', - facetQuery: 'Apple', - maxFacetHits: 10, - highlightPreTag: '', - highlightPostTag: '', - page: 5, - }), - }, - ]) - ); + expect(searchClient.search).toHaveBeenCalledTimes(1); + expect(searchClient.search).toHaveBeenCalledWith([ + { + type: 'facet', + indexName: 'indexName', + facet: 'brand', + params: expect.objectContaining({ + facetQuery: 'Apple', + query: 'Global Query', + maxFacetHits: 10, + highlightPreTag: '', + highlightPostTag: '', + page: 5, + }), + }, + ]); }); it('schedules a render on DerivedHelper results', async () => { diff --git a/packages/instantsearch.js/src/widgets/refinement-list/__tests__/refinement-list.test.tsx b/packages/instantsearch.js/src/widgets/refinement-list/__tests__/refinement-list.test.tsx index 6f0a7dc0ed..fc43c0af8a 100644 --- a/packages/instantsearch.js/src/widgets/refinement-list/__tests__/refinement-list.test.tsx +++ b/packages/instantsearch.js/src/widgets/refinement-list/__tests__/refinement-list.test.tsx @@ -1157,89 +1157,83 @@ describe('refinementList', () => { }); function createMockedSearchClient() { + const facetHits = [ + { + value: 'Apple', + highlighted: '__ais-highlight__App__/ais-highlight__le', + count: 442, + }, + { + value: 'Alpine', + highlighted: '__ais-highlight__Alp__/ais-highlight__ine', + count: 30, + }, + { + value: 'APC', + highlighted: '__ais-highlight__AP__/ais-highlight__C', + count: 24, + }, + { + value: 'Amped Wireless', + highlighted: '__ais-highlight__Amp__/ais-highlight__ed Wireless', + count: 4, + }, + { + value: "Applebee's", + highlighted: "__ais-highlight__App__/ais-highlight__lebee's", + count: 2, + }, + { + value: 'Amplicom', + highlighted: '__ais-highlight__Amp__/ais-highlight__licom', + count: 1, + }, + { + value: 'Apollo Enclosures', + highlighted: '__ais-highlight__Ap__/ais-highlight__ollo Enclosures', + count: 1, + }, + { + value: 'Apple®', + highlighted: '__ais-highlight__App__/ais-highlight__le®', + count: 1, + }, + { + value: 'Applica', + highlighted: '__ais-highlight__App__/ais-highlight__lica', + count: 1, + }, + { + value: 'Apricorn', + highlighted: '__ais-highlight__Ap__/ais-highlight__ricorn', + count: 1, + }, + ]; + return createSearchClient({ search: jest.fn((requests) => { return Promise.resolve( createMultiSearchResponse( - ...requests.map(() => - createSingleSearchResponse({ - facets: { - brand: { - Apple: 746, - Samsung: 633, - Metra: 591, - }, - }, - }) + ...requests.map((request) => + request.type === 'facet' + ? createSFFVResponse({ + facetHits: + request.params.facetQuery === 'query with no results' + ? [] + : facetHits, + }) + : createSingleSearchResponse({ + facets: { + brand: { + Apple: 746, + Samsung: 633, + Metra: 591, + }, + }, + }) ) ) ); }), - // @ts-ignore v5 does not have this method, but it's easier to have it here. In a future version we can replace this method and its usages with search({ type: 'facet }) - searchForFacetValues: jest.fn((requests) => { - return Promise.resolve([ - createSFFVResponse({ - facetHits: - // @ts-ignore for v5, which has a different definition of `searchForFacetValues` - requests[0].params.facetQuery === 'query with no results' - ? [] - : [ - { - value: 'Apple', - highlighted: '__ais-highlight__App__/ais-highlight__le', - count: 442, - }, - { - value: 'Alpine', - highlighted: '__ais-highlight__Alp__/ais-highlight__ine', - count: 30, - }, - { - value: 'APC', - highlighted: '__ais-highlight__AP__/ais-highlight__C', - count: 24, - }, - { - value: 'Amped Wireless', - highlighted: - '__ais-highlight__Amp__/ais-highlight__ed Wireless', - count: 4, - }, - { - value: "Applebee's", - highlighted: - "__ais-highlight__App__/ais-highlight__lebee's", - count: 2, - }, - { - value: 'Amplicom', - highlighted: '__ais-highlight__Amp__/ais-highlight__licom', - count: 1, - }, - { - value: 'Apollo Enclosures', - highlighted: - '__ais-highlight__Ap__/ais-highlight__ollo Enclosures', - count: 1, - }, - { - value: 'Apple®', - highlighted: '__ais-highlight__App__/ais-highlight__le®', - count: 1, - }, - { - value: 'Applica', - highlighted: '__ais-highlight__App__/ais-highlight__lica', - count: 1, - }, - { - value: 'Apricorn', - highlighted: '__ais-highlight__Ap__/ais-highlight__ricorn', - count: 1, - }, - ], - }), - ]); - }), }); } diff --git a/packages/react-instantsearch/src/widgets/__tests__/RefinementList.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/RefinementList.test.tsx index db939e5c7c..68f0f56011 100644 --- a/packages/react-instantsearch/src/widgets/__tests__/RefinementList.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/RefinementList.test.tsx @@ -73,33 +73,38 @@ function createMockedSearchClient(parameters: Record = {}) { search: jest.fn((requests) => { return Promise.resolve( createMultiSearchResponse( - ...requests.map(() => - createSingleSearchResponse({ - facets: { - brand: { - 'Insignia™': 746, - Samsung: 633, - Metra: 591, - HP: 530, - Apple: 442, - GE: 394, - Sony: 350, - Incipio: 320, - KitchenAid: 318, - Whirlpool: 298, - LG: 291, - Canon: 287, - Frigidaire: 275, - Speck: 216, - OtterBox: 214, - Epson: 204, - 'Dynex™': 184, - Dell: 174, - 'Hamilton Beach': 173, - Platinum: 155, - }, - }, - }) + ...requests.map((request) => + request.type === 'facet' + ? createSFFVResponse({ + facetHits: + request.params.facetQuery === 'nothing' ? [] : FACET_HITS, + }) + : createSingleSearchResponse({ + facets: { + brand: { + 'Insignia™': 746, + Samsung: 633, + Metra: 591, + HP: 530, + Apple: 442, + GE: 394, + Sony: 350, + Incipio: 320, + KitchenAid: 318, + Whirlpool: 298, + LG: 291, + Canon: 287, + Frigidaire: 275, + Speck: 216, + OtterBox: 214, + Epson: 204, + 'Dynex™': 184, + Dell: 174, + 'Hamilton Beach': 173, + Platinum: 155, + }, + }, + }) ) ) ); @@ -136,21 +141,7 @@ describe('RefinementList', () => { }); test('renders with translations', async () => { - const searchClient = createMockedSearchClient({ - searchForFacetValues: jest.fn( - ([ - { - params: { facetQuery }, - }, - ]) => { - return Promise.resolve([ - createSFFVResponse({ - facetHits: facetQuery === 'nothing' ? [] : FACET_HITS, - }), - ]); - } - ), - }); + const searchClient = createMockedSearchClient(); const { container, getByRole } = render( { expect(getByRole('button', { name: 'Submit' })).toBeInTheDocument(); + expect(searchClient.search).toHaveBeenCalledTimes(1); userEvent.type( container.querySelector('.ais-SearchBox-input') as HTMLInputElement, 'nothing' @@ -189,7 +181,7 @@ describe('RefinementList', () => { expect(getByRole('button', { name: 'Reset' })).toBeInTheDocument(); await waitFor(() => { - expect(searchClient.searchForFacetValues).toHaveBeenCalledTimes(7); + expect(searchClient.search).toHaveBeenCalledTimes(1 + 'nothing'.length); expect( container.querySelector('.ais-RefinementList-noResults') diff --git a/tests/common/widgets/refinement-list/options.ts b/tests/common/widgets/refinement-list/options.ts index 2c6f3c530e..e43431fba5 100644 --- a/tests/common/widgets/refinement-list/options.ts +++ b/tests/common/widgets/refinement-list/options.ts @@ -897,17 +897,22 @@ export function createOptionsTests( }); // One call per keystroke - expect(searchClient.searchForFacetValues).toHaveBeenCalledTimes(3); - expect(searchClient.searchForFacetValues).toHaveBeenLastCalledWith( - expect.arrayContaining([ - expect.objectContaining({ - params: expect.objectContaining({ - facetName: 'brand', - facetQuery: 'app', - }), - }), - ]) - ); + expect(searchClient.search).toHaveBeenCalledTimes(1 + 'app'.length); + expect(searchClient.search).toHaveBeenLastCalledWith([ + { + type: 'facet', + indexName: 'indexName', + facet: 'brand', + params: { + facetQuery: 'app', + facets: ['brand'], + highlightPostTag: '__/ais-highlight__', + highlightPreTag: '__ais-highlight__', + maxFacetHits: 10, + maxValuesPerFacet: 10, + }, + }, + ]); expect( document.querySelector('.ais-RefinementList-labelText') ).toMatchNormalizedInlineSnapshot( @@ -952,11 +957,7 @@ export function createOptionsTests( }); test('displays a fallback when there are no results', async () => { - const searchClient = createMockedSearchClient({ - searchForFacetValues: jest.fn(() => - Promise.resolve([createSFFVResponse({ facetHits: [] })]) - ), - }); + const searchClient = createMockedSearchClient(); await setup({ instantSearchOptions: { @@ -985,7 +986,7 @@ export function createOptionsTests( await wait(0); }); - expect(searchClient.searchForFacetValues).toHaveBeenCalledTimes(7); + expect(searchClient.search).toHaveBeenCalledTimes(1 + 'nothing'.length); expect( document.querySelector('.ais-RefinementList-noResults') @@ -1536,44 +1537,42 @@ function createMockedSearchClient(parameters: Record = {}) { search: jest.fn((requests) => { return Promise.resolve( createMultiSearchResponse( - ...requests.map(() => - createSingleSearchResponse({ - facets: { - brand: { - 'Insignia™': 746, - Samsung: 633, - Metra: 591, - HP: 530, - Apple: 442, - GE: 394, - Sony: 350, - Incipio: 320, - KitchenAid: 318, - Whirlpool: 298, - LG: 291, - Canon: 287, - Frigidaire: 275, - Speck: 216, - OtterBox: 214, - Epson: 204, - 'Dynex™': 184, - Dell: 174, - 'Hamilton Beach': 173, - Platinum: 155, - }, - }, - }) + ...requests.map((request) => + request.type === 'facet' + ? createSFFVResponse({ + facetHits: + request.params.facetQuery === 'nothing' ? [] : FACET_HITS, + }) + : createSingleSearchResponse({ + facets: { + brand: { + 'Insignia™': 746, + Samsung: 633, + Metra: 591, + HP: 530, + Apple: 442, + GE: 394, + Sony: 350, + Incipio: 320, + KitchenAid: 318, + Whirlpool: 298, + LG: 291, + Canon: 287, + Frigidaire: 275, + Speck: 216, + OtterBox: 214, + Epson: 204, + 'Dynex™': 184, + Dell: 174, + 'Hamilton Beach': 173, + Platinum: 155, + }, + }, + }) ) ) ); }), - searchForFacetValues: jest.fn(() => - Promise.resolve([ - createSFFVResponse({ - facetHits: FACET_HITS, - }), - ]) - ) as any, // @TODO: for now casted as any, because v5 only has `type: facet` in search ...parameters, }); } diff --git a/tests/mocks/createSearchClient.ts b/tests/mocks/createSearchClient.ts index ff87042767..b5cf5b3626 100644 --- a/tests/mocks/createSearchClient.ts +++ b/tests/mocks/createSearchClient.ts @@ -16,12 +16,14 @@ export const createSearchClient = ( search: jest.fn((requests) => Promise.resolve( createMultiSearchResponse( - ...requests.map(() => createSingleSearchResponse()) + ...requests.map((request) => + request.type === 'facet' + ? createSFFVResponse() + : createSingleSearchResponse() + ) ) ) ), - // @ts-ignore v5 does not have this method, but it's easier to have it here. In a future version we can replace this method and its usages with search({ type: 'facet }) - searchForFacetValues: jest.fn(() => Promise.resolve([createSFFVResponse()])), // @ts-ignore this allows us to test insights initialization without warning applicationID: 'appId', apiKey: 'apiKey',