diff --git a/package.json b/package.json index 8d1de8cc..c0259c95 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "test:build": "yarn build && jest --runInBand --selectProjects build", "test:e2e": "yarn local:env:setup && concurrently --kill-others -s first \"yarn local:env:react\" \"cypress run --env playground=local \"", "test:e2e:watch": "yarn local:env:setup && concurrently --kill-others -s first \"yarn local:env:react\" \"cypress open --env playground=local\"", - "test:all": "yarn test:e2e:all && yarn test && test:build", + "test:all": "yarn test:e2e && yarn test && yarn test:build", "cy:open": "cypress open", "playground:vue": "yarn --cwd ./playgrounds/vue && yarn --cwd ./playgrounds/vue serve", "playground:react": "yarn --cwd ./playgrounds/react && yarn --cwd ./playgrounds/react start", diff --git a/src/adapter/search-request-adapter/__tests__/search-params.tests.ts b/src/adapter/search-request-adapter/__tests__/search-params.tests.ts index ddaa8b82..280a7f1f 100644 --- a/src/adapter/search-request-adapter/__tests__/search-params.tests.ts +++ b/src/adapter/search-request-adapter/__tests__/search-params.tests.ts @@ -183,3 +183,29 @@ test('Adapt SearchContext with no finite pagination and pagination total hits lo expect(searchParams.limit).toBe(4) }) + +test('Adapt SearchContext placeholderSearch set to false', () => { + const searchParams = adaptSearchParams({ + indexUid: 'test', + query: '', + pagination: { paginationTotalHits: 4, page: 0, hitsPerPage: 6 }, + defaultFacetDistribution: {}, + finitePagination: false, + placeholderSearch: false, + }) + + expect(searchParams.limit).toBe(0) +}) + +test('Adapt SearchContext placeholderSearch set to false', () => { + const searchParams = adaptSearchParams({ + indexUid: 'test', + query: '', + pagination: { paginationTotalHits: 200, page: 0, hitsPerPage: 6 }, + defaultFacetDistribution: {}, + finitePagination: false, + placeholderSearch: true, + }) + + expect(searchParams.limit).toBe(7) +}) diff --git a/src/adapter/search-request-adapter/search-params-adapter.ts b/src/adapter/search-request-adapter/search-params-adapter.ts index 051b9466..606c43fe 100644 --- a/src/adapter/search-request-adapter/search-params-adapter.ts +++ b/src/adapter/search-request-adapter/search-params-adapter.ts @@ -59,8 +59,11 @@ export function adaptSearchParams( const placeholderSearch = searchContext.placeholderSearch const query = searchContext.query + + // Pagination const { pagination } = searchContext - // Limit + + // Limit based on pagination preferences if ( (!placeholderSearch && query === '') || pagination.paginationTotalHits === 0 diff --git a/src/adapter/search-request-adapter/search-resolver.ts b/src/adapter/search-request-adapter/search-resolver.ts index ea546bff..04ae6b10 100644 --- a/src/adapter/search-request-adapter/search-resolver.ts +++ b/src/adapter/search-request-adapter/search-resolver.ts @@ -7,6 +7,17 @@ import { } from '../../types' import { addMissingFacets, extractFacets } from './filters' +const emptySearch: MeiliSearchResponse> = { + hits: [], + query: '', + facetsDistribution: {}, + limit: 0, + offset: 0, + exhaustiveNbHits: false, + nbHits: 0, + processingTimeMs: 0, +} + /** * @param {ResponseCacher} cache */ @@ -23,6 +34,14 @@ export function SearchResolver(cache: SearchCacheInterface) { searchParams: MeiliSearchParams, client: MeiliSearch ): Promise>> { + const { placeholderSearch, query } = searchContext + + // query can be: empty string, undefined or null + // all of them are falsy's + if (!placeholderSearch && !query) { + return emptySearch + } + const { pagination } = searchContext // In case we are in a `finitePagination`, only one big request is made @@ -38,12 +57,11 @@ export function SearchResolver(cache: SearchCacheInterface) { searchContext.query, paginationCache, ]) - const entry = cache.getEntry(key) + const cachedResponse = cache.getEntry(key) - // Request is cached. - if (entry) return entry + // Check if specific request is already cached with its associated search response. + if (cachedResponse) return cachedResponse - // Cache filters: todo components const facetsCache = extractFacets(searchContext, searchParams) // Make search request diff --git a/src/client/instant-meilisearch-client.ts b/src/client/instant-meilisearch-client.ts index 263fe97c..2a4261e0 100644 --- a/src/client/instant-meilisearch-client.ts +++ b/src/client/instant-meilisearch-client.ts @@ -31,10 +31,9 @@ export function instantMeiliSearch( const searchResolver = SearchResolver(SearchCache()) // paginationTotalHits can be 0 as it is a valid number let defaultFacetDistribution: any = {} + const meilisearchClient = new MeiliSearch({ host: hostUrl, apiKey: apiKey }) return { - MeiliSearchClient: new MeiliSearch({ host: hostUrl, apiKey: apiKey }), - /** * @param {readonlyAlgoliaMultipleQueriesQuery[]} instantSearchRequests * @returns {Array} @@ -57,7 +56,7 @@ export function instantMeiliSearch( const searchResponse = await searchResolver.searchResponse( searchContext, adaptedSearchRequest, - this.MeiliSearchClient + meilisearchClient ) // Cache first facets distribution of the instantMeilisearch instance diff --git a/src/contexts/search-context.ts b/src/contexts/search-context.ts index 8bbe29bc..aeedd190 100644 --- a/src/contexts/search-context.ts +++ b/src/contexts/search-context.ts @@ -26,6 +26,7 @@ export function createSearchContext( hitsPerPage: instantSearchParams?.hitsPerPage, page: instantSearchParams?.page, }) + const searchContext: SearchContext = { ...options, ...instantSearchParams, @@ -33,7 +34,7 @@ export function createSearchContext( indexUid, pagination, defaultFacetDistribution, - placeholderSearch: !options.placeholderSearch, // true by default + placeholderSearch: options.placeholderSearch !== false, // true by default keepZeroFacets: !!options.keepZeroFacets, // false by default finitePagination: !!options.finitePagination, // false by default } diff --git a/src/types/types.ts b/src/types/types.ts index cedd3bab..a54d7a78 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -68,6 +68,7 @@ export type PaginationContext = { hitsPerPage: number page: number } + export type PaginationParams = { paginationTotalHits?: number hitsPerPage?: number @@ -84,6 +85,4 @@ export type SearchContext = Omit< pagination: PaginationContext } -export type InstantMeiliSearchInstance = SearchClient & { - MeiliSearchClient: MeiliSearch -} +export type InstantMeiliSearchInstance = SearchClient diff --git a/tests/assets/utils.ts b/tests/assets/utils.ts index a1247ea9..5a476277 100644 --- a/tests/assets/utils.ts +++ b/tests/assets/utils.ts @@ -1,4 +1,5 @@ import { instantMeiliSearch } from '../../src' +import { MeiliSearch } from 'meilisearch' const dataset = [ { @@ -223,5 +224,15 @@ const wrongSearchClient = instantMeiliSearch( 'http://localhost:7777', 'masterKey' ) +const meilisearchClient = new MeiliSearch({ + host: 'http://localhost:7700', + apiKey: 'masterKey', +}) -export { searchClient, dataset, wrongSearchClient, geoDataset } +export { + searchClient, + dataset, + wrongSearchClient, + geoDataset, + meilisearchClient, +} diff --git a/tests/base.tests.ts b/tests/base.tests.ts deleted file mode 100644 index 967c56e7..00000000 --- a/tests/base.tests.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { instantMeiliSearch } from '../src/index' - -test('Should test if instantMeiliSearch Client is created correctly', () => { - const client = instantMeiliSearch('http://localhost:7700', 'masterKey') - expect(client.search).toBeDefined() - expect(client.MeiliSearchClient).toBeDefined() -}) diff --git a/tests/build.tests.js b/tests/build.tests.js index 656a125b..1f98f270 100644 --- a/tests/build.tests.js +++ b/tests/build.tests.js @@ -10,11 +10,11 @@ const CJSclient = CJSinstantMeiliSearch('http://localhost:7700', 'masterKey') const instantsearch = require('instantsearch.js') test('UMD client should correctly created', () => { - expect(UMDclient.MeiliSearchClient.config.apiKey).toBe('masterKey') + expect(UMDclient.search).not.toBeUndefined() }) test('CJS client should correctly created', () => { - expect(CJSclient.MeiliSearchClient.config.apiKey).toBe('masterKey') + expect(CJSclient.search).not.toBeUndefined() }) test('CJS instantsearch client should correctly created', () => { @@ -23,9 +23,7 @@ test('CJS instantsearch client should correctly created', () => { searchClient: CJSclient, }) expect(CJSInstantSearch.indexName).toBe('cjs_index') - expect(CJSInstantSearch.client.MeiliSearchClient.config.apiKey).toBe( - 'masterKey' - ) + expect(CJSInstantSearch.client.search).not.toBeUndefined() }) test('UMD instantsearch client should correctly created', () => { @@ -34,7 +32,5 @@ test('UMD instantsearch client should correctly created', () => { searchClient: UMDclient, }) expect(UMDInstantSearch.indexName).toBe('umd_index') - expect(UMDInstantSearch.client.MeiliSearchClient.config.apiKey).toBe( - 'masterKey' - ) + expect(UMDInstantSearch.client.search).not.toBeUndefined() }) diff --git a/tests/configure.attributes-to-retrieve.tests.ts b/tests/configure.attributes-to-retrieve.tests.ts index 2ea4e3e4..4b74732c 100644 --- a/tests/configure.attributes-to-retrieve.tests.ts +++ b/tests/configure.attributes-to-retrieve.tests.ts @@ -1,18 +1,19 @@ -import { searchClient, dataset, Movies } from './assets/utils' +import { + searchClient, + dataset, + Movies, + meilisearchClient, +} from './assets/utils' describe('Instant Meilisearch Browser test', () => { beforeAll(async () => { - const deleteTask = await searchClient.MeiliSearchClient.deleteIndex( - 'movies' - ) - await searchClient.MeiliSearchClient.waitForTask(deleteTask.uid) + const deleteTask = await meilisearchClient.deleteIndex('movies') + await meilisearchClient.waitForTask(deleteTask.uid) - const documentsTask = await searchClient.MeiliSearchClient.index( - 'movies' - ).addDocuments(dataset) - await searchClient.MeiliSearchClient.index('movies').waitForTask( - documentsTask.uid - ) + const documentsTask = await meilisearchClient + .index('movies') + .addDocuments(dataset) + await meilisearchClient.index('movies').waitForTask(documentsTask.uid) }) test('Test attributesToRetrieve on no attributes', async () => { diff --git a/tests/facets-distribution.tests.ts b/tests/facets-distribution.tests.ts index 58f54641..68bbf1c7 100644 --- a/tests/facets-distribution.tests.ts +++ b/tests/facets-distribution.tests.ts @@ -1,20 +1,16 @@ -import { searchClient, dataset } from './assets/utils' +import { searchClient, dataset, meilisearchClient } from './assets/utils' describe('Instant Meilisearch Browser test', () => { beforeAll(async () => { - const deleteTask = await searchClient.MeiliSearchClient.deleteIndex( - 'movies' - ) - await searchClient.MeiliSearchClient.waitForTask(deleteTask.uid) - await searchClient.MeiliSearchClient.index( - 'movies' - ).updateFilterableAttributes(['genres']) - const documentsTask = await searchClient.MeiliSearchClient.index( - 'movies' - ).addDocuments(dataset) - await searchClient.MeiliSearchClient.index('movies').waitForTask( - documentsTask.uid - ) + const deleteTask = await meilisearchClient.deleteIndex('movies') + await meilisearchClient.waitForTask(deleteTask.uid) + await meilisearchClient + .index('movies') + .updateFilterableAttributes(['genres']) + const documentsTask = await meilisearchClient + .index('movies') + .addDocuments(dataset) + await meilisearchClient.index('movies').waitForTask(documentsTask.uid) }) test('Test empty array on facetsDistribution', async () => { diff --git a/tests/filter.tests.ts b/tests/filter.tests.ts index 72a4306a..7c39ce8b 100644 --- a/tests/filter.tests.ts +++ b/tests/filter.tests.ts @@ -1,20 +1,21 @@ -import { searchClient, dataset, Movies } from './assets/utils' +import { + searchClient, + dataset, + Movies, + meilisearchClient, +} from './assets/utils' describe('Instant Meilisearch Browser test', () => { beforeAll(async () => { - const deleteTask = await searchClient.MeiliSearchClient.deleteIndex( - 'movies' - ) - await searchClient.MeiliSearchClient.waitForTask(deleteTask.uid) - await searchClient.MeiliSearchClient.index( - 'movies' - ).updateFilterableAttributes(['genres', 'title']) - const documentsTask = await searchClient.MeiliSearchClient.index( - 'movies' - ).addDocuments(dataset) - await searchClient.MeiliSearchClient.index('movies').waitForTask( - documentsTask.uid - ) + const deleteTask = await meilisearchClient.deleteIndex('movies') + await meilisearchClient.waitForTask(deleteTask.uid) + await meilisearchClient + .index('movies') + .updateFilterableAttributes(['genres', 'title']) + const documentsTask = await meilisearchClient + .index('movies') + .addDocuments(dataset) + await meilisearchClient.index('movies').waitForTask(documentsTask.uid) }) test('Test one string facet on filter without a query', async () => { diff --git a/tests/geosearch.tests.ts b/tests/geosearch.tests.ts index 5955a657..25504d89 100644 --- a/tests/geosearch.tests.ts +++ b/tests/geosearch.tests.ts @@ -1,23 +1,22 @@ -import { searchClient, geoDataset, City } from './assets/utils' +import { + searchClient, + geoDataset, + City, + meilisearchClient, +} from './assets/utils' describe('Instant Meilisearch Browser test', () => { beforeAll(async () => { - const deleteTask = await searchClient.MeiliSearchClient.deleteIndex( - 'geotest' - ) - await searchClient.MeiliSearchClient.waitForTask(deleteTask.uid) - await searchClient.MeiliSearchClient.index( - 'geotest' - ).updateFilterableAttributes(['_geo']) - await searchClient.MeiliSearchClient.index( - 'geotest' - ).updateSortableAttributes(['_geo']) - const documentsTask = await searchClient.MeiliSearchClient.index( - 'geotest' - ).addDocuments(geoDataset) - await searchClient.MeiliSearchClient.index('movies').waitForTask( - documentsTask.uid - ) + const deleteTask = await meilisearchClient.deleteIndex('geotest') + await meilisearchClient.waitForTask(deleteTask.uid) + await meilisearchClient + .index('geotest') + .updateFilterableAttributes(['_geo']) + await meilisearchClient.index('geotest').updateSortableAttributes(['_geo']) + const documentsTask = await meilisearchClient + .index('geotest') + .addDocuments(geoDataset) + await meilisearchClient.index('movies').waitForTask(documentsTask.uid) }) test('Test aroundRadius and aroundLatLng in geo search', async () => { diff --git a/tests/highlight.tests.ts b/tests/highlight.tests.ts index 5c40fe52..de2886a1 100644 --- a/tests/highlight.tests.ts +++ b/tests/highlight.tests.ts @@ -1,20 +1,21 @@ -import { searchClient, dataset, Movies } from './assets/utils' +import { + searchClient, + dataset, + Movies, + meilisearchClient, +} from './assets/utils' describe('Highlight Browser test', () => { beforeAll(async () => { - const deleteTask = await searchClient.MeiliSearchClient.deleteIndex( - 'movies' - ) - await searchClient.MeiliSearchClient.waitForTask(deleteTask.uid) - await searchClient.MeiliSearchClient.index( - 'movies' - ).updateFilterableAttributes(['genres']) - const documentsTask = await searchClient.MeiliSearchClient.index( - 'movies' - ).addDocuments(dataset) - await searchClient.MeiliSearchClient.index('movies').waitForTask( - documentsTask.uid - ) + const deleteTask = await meilisearchClient.deleteIndex('movies') + await meilisearchClient.waitForTask(deleteTask.uid) + await meilisearchClient + .index('movies') + .updateFilterableAttributes(['genres']) + const documentsTask = await meilisearchClient + .index('movies') + .addDocuments(dataset) + await meilisearchClient.index('movies').waitForTask(documentsTask.uid) }) test('Test one attributesToHighlight on wrong attribute placeholder', async () => { diff --git a/tests/pagination.tests.ts b/tests/pagination.tests.ts index 8ff8742b..22a0adeb 100644 --- a/tests/pagination.tests.ts +++ b/tests/pagination.tests.ts @@ -1,21 +1,22 @@ import { instantMeiliSearch } from '../src' -import { searchClient, dataset, Movies } from './assets/utils' +import { + searchClient, + dataset, + Movies, + meilisearchClient, +} from './assets/utils' describe('Pagination browser test', () => { beforeAll(async () => { - const deleteTask = await searchClient.MeiliSearchClient.deleteIndex( - 'movies' - ) - await searchClient.MeiliSearchClient.waitForTask(deleteTask.uid) - await searchClient.MeiliSearchClient.index( - 'movies' - ).updateFilterableAttributes(['genres']) - const documentsTask = await searchClient.MeiliSearchClient.index( - 'movies' - ).addDocuments(dataset) - await searchClient.MeiliSearchClient.index('movies').waitForTask( - documentsTask.uid - ) + const deleteTask = await meilisearchClient.deleteIndex('movies') + await meilisearchClient.waitForTask(deleteTask.uid) + await meilisearchClient + .index('movies') + .updateFilterableAttributes(['genres']) + const documentsTask = await meilisearchClient + .index('movies') + .addDocuments(dataset) + await meilisearchClient.index('movies').waitForTask(documentsTask.uid) }) test('Test 1 hitsPerPage', async () => { diff --git a/tests/placeholder-search.tests.ts b/tests/placeholder-search.tests.ts new file mode 100644 index 00000000..611a361a --- /dev/null +++ b/tests/placeholder-search.tests.ts @@ -0,0 +1,57 @@ +import { instantMeiliSearch } from '../src' +import { + searchClient, + dataset, + Movies, + meilisearchClient, +} from './assets/utils' + +describe('Pagination browser test', () => { + beforeAll(async () => { + const deleteTask = await meilisearchClient.deleteIndex('movies') + await meilisearchClient.waitForTask(deleteTask.uid) + await meilisearchClient + .index('movies') + .updateFilterableAttributes(['genres']) + const documentsTask = await meilisearchClient + .index('movies') + .addDocuments(dataset) + await meilisearchClient.index('movies').waitForTask(documentsTask.uid) + }) + + test('Test placeholdersearch set to false', async () => { + const customClient = instantMeiliSearch( + 'http://localhost:7700', + 'masterKey', + { + paginationTotalHits: 5, + placeholderSearch: true, + } + ) + const response = await customClient.search([ + { + indexName: 'movies', + }, + ]) + const hits = response.results[0].hits + expect(hits.length).toBe(5) + }) + + test('Test placeholdersearch set to true', async () => { + const customClient = instantMeiliSearch( + 'http://localhost:7700', + 'masterKey', + { + paginationTotalHits: 5, + placeholderSearch: false, + } + ) + const response = await customClient.search([ + { + indexName: 'movies', + }, + ]) + const hits = response.results[0].hits + expect(hits.length).toBe(0) + }) +}) diff --git a/tests/snippets.tests.ts b/tests/snippets.tests.ts index bb44ffa2..ce63d6fa 100644 --- a/tests/snippets.tests.ts +++ b/tests/snippets.tests.ts @@ -1,20 +1,21 @@ -import { searchClient, dataset, Movies } from './assets/utils' +import { + searchClient, + dataset, + Movies, + meilisearchClient, +} from './assets/utils' describe('Snippet Browser test', () => { beforeAll(async () => { - const deleteTask = await searchClient.MeiliSearchClient.deleteIndex( - 'movies' - ) - await searchClient.MeiliSearchClient.waitForTask(deleteTask.uid) - await searchClient.MeiliSearchClient.index( - 'movies' - ).updateFilterableAttributes(['genres']) - const documentsTask = await searchClient.MeiliSearchClient.index( - 'movies' - ).addDocuments(dataset) - await searchClient.MeiliSearchClient.index('movies').waitForTask( - documentsTask.uid - ) + const deleteTask = await meilisearchClient.deleteIndex('movies') + await meilisearchClient.waitForTask(deleteTask.uid) + await meilisearchClient + .index('movies') + .updateFilterableAttributes(['genres']) + const documentsTask = await meilisearchClient + .index('movies') + .addDocuments(dataset) + await meilisearchClient.index('movies').waitForTask(documentsTask.uid) }) test('Test one attributesToSnippet on placeholder', async () => {