diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index c703765cf..b7e7a0534 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -273,7 +273,7 @@ search_parameter_guide_highlight_tag_1: |- }) search_parameter_guide_matches_1: |- client.index('movies').search('winter feast', { - matches: true + showMatchesPosition: true }) settings_guide_synonyms_1: |- client.index('tops').updateSettings({ @@ -497,7 +497,7 @@ faceted_search_filter_1: |- faceted_search_facets_distribution_1: |- client.index('movies') .search('Batman', { - facetsDistribution: ['genres'] + facets: ['genres'] }) faceted_search_walkthrough_filter_1: |- client.index('movies') @@ -506,8 +506,6 @@ faceted_search_walkthrough_filter_1: |- }) post_dump_1: |- client.createDump() -get_dump_status_1: |- - client.getDumpStatus('20201101-110357260') phrase_search_1: |- client.index('movies') .search('"african american" horror') diff --git a/.github/scripts/check-release.sh b/.github/scripts/check-release.sh index 22ea2636f..278bc40e9 100644 --- a/.github/scripts/check-release.sh +++ b/.github/scripts/check-release.sh @@ -2,10 +2,18 @@ # Checking if current tag matches the package version current_tag=$(echo $GITHUB_REF | cut -d '/' -f 3 | tr -d ' ',v) -file_tag=$(grep '"version":' package.json | cut -d ':' -f 2- | tr -d ' ' | tr -d '"' | tr -d ',') -if [ "$current_tag" != "$file_tag" ]; then + +package_json_version=$(grep '"version":' package.json | cut -d ':' -f 2- | tr -d ' ' | tr -d '"' | tr -d ',') +if [ "$current_tag" != "$package_json_version" ]; then echo "Error: the current tag does not match the version in package file(s)." - echo "$current_tag vs $file_tag" + echo "$current_tag vs $package_json_version" + exit 1 +fi + +package_version_ts=$(grep "PACKAGE_VERSION =" src/package-version.ts | cut -d "=" -f 2- | tr -d " " | tr -d "'") +if [ "$current_tag" != "$package_version_ts" ]; then + echo "Error: the current tag does not match the version in src/package-version.ts." + echo "$current_tag vs $package_version_ts" exit 1 fi diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5a051c25c..6b2081b7a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -115,12 +115,18 @@ _[Read more about this](https://github.com/meilisearch/integration-guides/blob/m ⚠️ Before doing anything, make sure you got through the guide about [Releasing an Integration](https://github.com/meilisearch/integration-guides/blob/main/resources/integration-release.md). -Make a PR modifying the file [`package.json`](/package.json) with the right version. +Make a PR modifying the following files with the right version: +[`package.json`](/package.json): ```javascript "version": "X.X.X", ``` +[`src/package-version`](/src/package-version.ts) +```javascript +export const PACKAGE_VERSION = 'X.X.X' +``` + Once the changes are merged on `main`, you can publish the current draft release via the [GitHub interface](https://github.com/meilisearch/meilisearch-js/releases): on this page, click on `Edit` (related to the draft release) > update the description (be sure you apply [these recommandations](https://github.com/meilisearch/integration-guides/blob/main/resources/integration-release.md#writting-the-release-description)) > when you are ready, click on `Publish release`. GitHub Actions will be triggered and push the package to [npm](https://www.npmjs.com/package/meilisearch). diff --git a/README.md b/README.md index b978cb97b..9a8fb8836 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,7 @@ Output: ], "offset": 0, "limit": 20, - "nbHits": 1, + "estimatedTotalHits": 1, "processingTimeMs": 1, "query": "philoudelphia" } @@ -227,7 +227,7 @@ await index.search( ], "offset": 0, "limit": 20, - "nbHits": 1, + "estimatedTotalHits": 1, "processingTimeMs": 0, "query": "wonder" } @@ -270,7 +270,7 @@ await index.search( ], "offset": 0, "limit": 20, - "nbHits": 1, + "estimatedTotalHits": 1, "processingTimeMs": 0, "query": "wonder" } @@ -285,7 +285,7 @@ await index.search( '', { filter: ['genres = fantasy'], - facetsDistribution: ['genres'] + facets: ['genres'] } ) ``` @@ -306,10 +306,10 @@ await index.search( ], "offset": 0, "limit": 20, - "nbHits": 2, + "estimatedTotalHits": 2, "processingTimeMs": 0, "query": "", - "facetsDistribution": { + "facetDistribution": { "genres": { "Action": 2, "Fantasy": 1, @@ -342,7 +342,7 @@ controller.abort() ## 🤖 Compatibility with Meilisearch -This package only guarantees the compatibility with the [version v0.27.0 of Meilisearch](https://github.com/meilisearch/meilisearch/releases/tag/v0.27.0). +This package only guarantees the compatibility with the [version v0.28.0 of Meilisearch](https://github.com/meilisearch/meilisearch/releases/tag/v0.28.0). ## 💡 Learn More @@ -393,7 +393,7 @@ If you want to know more about the development workflow or want to contribute, p - [Get Documents](https://docs.meilisearch.com/reference/api/documents.html#get-documents): -`index.getDocuments(params: getDocumentsParams): Promise[]>` +`index.getDocuments(parameters: DocumentsQuery = {}): Promise>>` - [Get one document](https://docs.meilisearch.com/reference/api/documents.html#get-one-document): @@ -413,47 +413,44 @@ If you want to know more about the development workflow or want to contribute, p ### Tasks -- [Get task info using the client](https://docs.meilisearch.com/reference/api/tasks.html#get-all-tasks): +- [Get all tasks](https://docs.meilisearch.com/reference/api/tasks.html#get-all-tasks) -Task list: -`client.getTasks(): Promise>` + `client.getTasks(parameters: TasksQuery): Promise` -One task: -`client.getTask(uid: number): Promise` +- [Get one task](https://docs.meilisearch.com/reference/api/tasks.html#get-task) -- [Get task info using the index](https://docs.meilisearch.com/reference/api/tasks.html#get-all-tasks-by-index): + `client.getTask(uid: number): Promise` -Task list: -`index.getTasks(): Promise>` +- [Get all tasks of an index](https://docs.meilisearch.com/reference/api/tasks.html#get-all-tasks-by-index) -One task: -`index.getTask(uid: number): Promise` + `index.getTasks(parameters: TasksQuery): Promise` + +- [Get one task of an index](https://docs.meilisearch.com/reference/api/tasks.html#get-task) + + `index.getTask(uid: number): Promise` - Wait for one task: -Using de client: -`client.waitForTask(uid: number, { timeOutMs?: number, intervalMs?: number }): Promise` + `client.waitForTask(uid: number, { timeOutMs?: number, intervalMs?: number }): Promise` -Using the index: -`index.waitForTask(uid: number, { timeOutMs?: number, intervalMs?: number }): Promise` + With an index instance: + `index.waitForTask(uid: number, { timeOutMs?: number, intervalMs?: number }): Promise` - Wait for multiple tasks: + `client.waitForTasks(uids: number[], { timeOutMs?: number, intervalMs?: number }): Promise` -Using the client: -`client.waitForTasks(uids: number[], { timeOutMs?: number, intervalMs?: number }): Promise>` - -Using the index: -`index.waitForTasks(uids: number[], { timeOutMs?: number, intervalMs?: number }): Promise>` + With an index instance: + `index.waitForTasks(uids: number[], { timeOutMs?: number, intervalMs?: number }): Promise` ### Indexes -- [Get all indexes in Index instances](https://docs.meilisearch.com/reference/api/indexes.html#list-all-indexes): +- [Get all indexes as Index instances](https://docs.meilisearch.com/reference/api/indexes.html#list-all-indexes): -`client.getIndexes(): Promise` +`client.getIndexes(parameters: IndexesQuery): Promise>` -- [Get raw indexes in JSON response from Meilisearch](https://docs.meilisearch.com/reference/api/indexes.html#list-all-indexes): +- [Get all indexes](https://docs.meilisearch.com/reference/api/indexes.html#list-all-indexes): -`client.getRawIndexes(): Promise` +`client.getRawIndexes(parameters: IndexesQuery): Promise>` - [Create a new index](https://docs.meilisearch.com/reference/api/indexes.html#create-an-index): @@ -467,10 +464,10 @@ Using the index: `client.getIndex(uid: string): Promise>` - [Get the raw index JSON response from Meilisearch](https://docs.meilisearch.com/reference/api/indexes.html#get-one-index): -`client.getRawIndex(uid: string): Promise` +`client.getRawIndex(uid: string): Promise` - [Get an object with information about the index](https://docs.meilisearch.com/reference/api/indexes.html#get-one-index): -`index.getRawInfo(): Promise` +`index.getRawInfo(): Promise` - [Update Index](https://docs.meilisearch.com/reference/api/indexes.html#update-an-index): @@ -620,23 +617,23 @@ Using the index object: - [Get keys](https://docs.meilisearch.com/reference/api/keys.html#get-all-keys): -`client.getKeys(): Promise>` +`client.getKeys(parameters: KeysQuery): Promise` - [Get one key](https://docs.meilisearch.com/reference/api/keys.html#get-one-key): -`client.getKey(key: string): Promise` +`client.getKey(keyOrUid: string): Promise` - [Create a key](https://docs.meilisearch.com/reference/api/keys.html#create-a-key): -`client.createKey(options: KeyPayload): Promise` +`client.createKey(options: KeyCreation): Promise` - [Update a key](https://docs.meilisearch.com/reference/api/keys.html#update-a-key): -`client.updateKey(key: string, options: KeyPayload): Promise` +`client.updateKey(keyOrUid: string, options: KeyUpdate): Promise` - [Delete a key](https://docs.meilisearch.com/reference/api/keys.html#delete-a-key): -`client.deleteKey(key: string): Promise` +`client.deleteKey(keyOrUid: string): Promise` ### isHealthy @@ -666,11 +663,7 @@ Using the index object: - [Trigger a dump creation process](https://docs.meilisearch.com/reference/api/dump.html#create-a-dump): -`client.createDump(): Promise` - -- [Get the status of a dump creation process](https://docs.meilisearch.com/reference/api/dump.html#get-dump-status): - -`client.getDumpStatus(dumpUid: string): Promise` +`client.createDump(): Promise`
diff --git a/playgrounds/javascript/src/app.js b/playgrounds/javascript/src/app.js index 77ec9a680..c3fcd74ef 100644 --- a/playgrounds/javascript/src/app.js +++ b/playgrounds/javascript/src/app.js @@ -10,8 +10,8 @@ const indexUid = 'movies' const addDataset = async () => { await client.deleteIndex(indexUid) - const { uid } = await client.createIndex(indexUid) - await client.index(indexUid).waitForTask(uid) + const { taskUid } = await client.createIndex(indexUid) + await client.index(indexUid).waitForTask(taskUid) const documents = await client.index(indexUid).getDocuments() @@ -27,9 +27,9 @@ const addDataset = async () => { { id: 5, title: 'Moana', genres: ['Fantasy', 'Action'] }, { id: 6, title: 'Philadelphia', genres: ['Drama'] }, ] - if (documents.length === 0) { - const task = await client.index(indexUid).addDocuments(dataset) - await client.index(indexUid).waitForTask(task.uid) + if (documents.results.length === 0) { + const { taskUid } = await client.index(indexUid).addDocuments(dataset) + await client.index(indexUid).waitForTask(taskUid) } } diff --git a/src/clients/client.ts b/src/clients/client.ts index aa94e0abb..ca44a1697 100644 --- a/src/clients/client.ts +++ b/src/clients/client.ts @@ -9,21 +9,27 @@ import { Index } from '../indexes' import { - KeyPayload, + KeyCreation, Config, IndexOptions, - IndexResponse, + IndexObject, EnqueuedTask, Key, Health, Stats, Version, - EnqueuedDump, ErrorStatusCode, Task, - Result, TokenSearchRules, TokenOptions, + TasksQuery, + WaitOptions, + KeyUpdate, + IndexesQuery, + IndexesResults, + KeysQuery, + KeysResults, + TasksResults, } from '../types' import { HttpRequests } from '../http-requests' import { TaskClient } from '../task' @@ -74,9 +80,9 @@ class Client { * @memberof MeiliSearch * @method getRawIndex * @param {string} indexUid The index UID - * @returns {Promise} Promise returning index information + * @returns {Promise} Promise returning index information */ - async getRawIndex(indexUid: string): Promise { + async getRawIndex(indexUid: string): Promise { return new Index(this.config, indexUid).getRawInfo() } @@ -84,25 +90,36 @@ class Client { * Get all the indexes as Index instances. * @memberof MeiliSearch * @method getIndexes - * @returns {Promise} Promise returning array of raw index information + * @param {IndexesQuery} [parameters={}] - Parameters to browse the indexes + * + * @returns {Promise>} Promise returning array of raw index information */ - async getIndexes(): Promise { - const response = await this.getRawIndexes() - const indexes: Index[] = response.map( + async getIndexes( + parameters: IndexesQuery = {} + ): Promise> { + const rawIndexes = await this.getRawIndexes(parameters) + const indexes: Index[] = rawIndexes.results.map( (index) => new Index(this.config, index.uid, index.primaryKey) ) - return indexes + return { ...rawIndexes, results: indexes } } /** * Get all the indexes in their raw value (no Index instances). * @memberof MeiliSearch * @method getRawIndexes - * @returns {Promise} Promise returning array of raw index information + * @param {IndexesQuery} [parameters={}] - Parameters to browse the indexes + * + * @returns {Promise>} Promise returning array of raw index information */ - async getRawIndexes(): Promise { + async getRawIndexes( + parameters: IndexesQuery = {} + ): Promise> { const url = `indexes` - return await this.httpRequest.get(url) + return await this.httpRequest.get>( + url, + parameters + ) } /** @@ -175,63 +192,61 @@ class Client { * Get the list of all client tasks * @memberof MeiliSearch * @method getTasks - * @returns {Promise>} - Promise returning all tasks + * @param {TasksQuery} [parameters={}] - Parameters to browse the tasks + * + * @returns {Promise} - Promise returning all tasks */ - async getTasks(): Promise> { - return await this.tasks.getClientTasks() + async getTasks(parameters: TasksQuery = {}): Promise { + return await this.tasks.getTasks(parameters) } /** * Get one task on the client scope * @memberof MeiliSearch * @method getTask - * @param {number} taskId - Task identifier + * @param {number} taskUid - Task identifier * @returns {Promise} - Promise returning a task */ - async getTask(taskId: number): Promise { - return await this.tasks.getClientTask(taskId) + async getTask(taskUid: number): Promise { + return await this.tasks.getTask(taskUid) } /** - * Wait for a batch of tasks to be processed. + * Wait for multiple tasks to be finished. + * * @memberof MeiliSearch * @method waitForTasks - * @param {number[]} taskIds - Tasks identifier + * @param {number[]} taskUids - Tasks identifier * @param {WaitOptions} waitOptions - Options on timeout and interval * - * @returns {Promise>} - Promise returning an array of tasks + * @returns {Promise} - Promise returning an array of tasks */ async waitForTasks( - taskIds: number[], - { - timeOutMs = 5000, - intervalMs = 50, - }: { timeOutMs?: number; intervalMs?: number } = {} - ): Promise> { - return await this.tasks.waitForClientTasks(taskIds, { + taskUids: number[], + { timeOutMs = 5000, intervalMs = 50 }: WaitOptions = {} + ): Promise { + return await this.tasks.waitForTasks(taskUids, { timeOutMs, intervalMs, }) } /** - * Wait for a task to be processed. + * Wait for a task to be finished. * * @memberof MeiliSearch * @method waitForTask - * @param {number} taskId - Task identifier + * + * @param {number} taskUid - Task identifier * @param {WaitOptions} waitOptions - Options on timeout and interval * * @returns {Promise} - Promise returning an array of tasks */ async waitForTask( - taskId: number, - { - timeOutMs = 5000, - intervalMs = 50, - }: { timeOutMs?: number; intervalMs?: number } = {} + taskUid: number, + { timeOutMs = 5000, intervalMs = 50 }: WaitOptions = {} ): Promise { - return await this.tasks.waitForClientTask(taskId, { + return await this.tasks.waitForTask(taskUid, { timeOutMs, intervalMs, }) @@ -245,11 +260,13 @@ class Client { * Get all API keys * @memberof MeiliSearch * @method getKeys - * @returns {Promise} Promise returning an object with keys + * @param {KeysQuery} [parameters={}] - Parameters to browse the indexes + * + * @returns {Promise} Promise returning an object with keys */ - async getKeys(): Promise> { + async getKeys(parameters: KeysQuery = {}): Promise { const url = `keys` - return await this.httpRequest.get>(url) + return await this.httpRequest.get(url, parameters) } /** @@ -257,11 +274,11 @@ class Client { * @memberof MeiliSearch * @method getKey * - * @param {string} key - Key + * @param {string} keyOrUid - Key or uid of the API key * @returns {Promise} Promise returning a key */ - async getKey(key: string): Promise { - const url = `keys/${key}` + async getKey(keyOrUid: string): Promise { + const url = `keys/${keyOrUid}` return await this.httpRequest.get(url) } @@ -270,10 +287,10 @@ class Client { * @memberof MeiliSearch * @method createKey * - * @param {KeyPayload} options - Key options + * @param {KeyCreation} options - Key options * @returns {Promise} Promise returning a key */ - async createKey(options: KeyPayload): Promise { + async createKey(options: KeyCreation): Promise { const url = `keys` return await this.httpRequest.post(url, options) } @@ -283,12 +300,12 @@ class Client { * @memberof MeiliSearch * @method updateKey * - * @param {string} key - Key - * @param {KeyPayload} options - Key options + * @param {string} keyOrUid - Key + * @param {KeyUpdate} options - Key options * @returns {Promise} Promise returning a key */ - async updateKey(key: string, options: KeyPayload): Promise { - const url = `keys/${key}` + async updateKey(keyOrUid: string, options: KeyUpdate): Promise { + const url = `keys/${keyOrUid}` return await this.httpRequest.patch(url, options) } @@ -297,11 +314,11 @@ class Client { * @memberof MeiliSearch * @method deleteKey * - * @param {string} key - Key + * @param {string} keyOrUid - Key * @returns {Promise} */ - async deleteKey(key: string): Promise { - const url = `keys/${key}` + async deleteKey(keyOrUid: string): Promise { + const url = `keys/${keyOrUid}` return await this.httpRequest.delete(url) } @@ -371,38 +388,33 @@ class Client { /// /** - * Triggers a dump creation process + * Creates a dump * @memberof MeiliSearch * @method createDump - * @returns {Promise} Promise returning object of the enqueued task + * @returns {Promise} Promise returning object of the enqueued task */ - async createDump(): Promise { + async createDump(): Promise { const url = `dumps` - return await this.httpRequest.post(url) + return await this.httpRequest.post(url) } - /** - * Get the status of a dump creation process - * @memberof MeiliSearch - * @method getDumpStatus - * @param {string} dumpUid Dump UID - * @returns {Promise} Promise returning object of the enqueued task - */ - async getDumpStatus(dumpUid: string): Promise { - const url = `dumps/${dumpUid}/status` - return await this.httpRequest.get(url) - } + /// + /// TOKENS + /// /** * Generate a tenant token * * @memberof MeiliSearch * @method generateTenantToken + * @param {apiKeyUid} apiKeyUid The uid of the api key used as issuer of the token. * @param {SearchRules} searchRules Search rules that are applied to every search. * @param {TokenOptions} options Token options to customize some aspect of the token. + * * @returns {String} The token in JWT format. */ generateTenantToken( + _apiKeyUid: string, _searchRules: TokenSearchRules, _options?: TokenOptions ): string { diff --git a/src/clients/node-client.ts b/src/clients/node-client.ts index 08f4fddce..113d134fc 100644 --- a/src/clients/node-client.ts +++ b/src/clients/node-client.ts @@ -15,18 +15,21 @@ class MeiliSearch extends Client { * * @memberof MeiliSearch * @method generateTenantToken + * @param {apiKeyUid} apiKeyUid The uid of the api key used as issuer of the token. * @param {SearchRules} searchRules Search rules that are applied to every search. * @param {TokenOptions} options Token options to customize some aspect of the token. + * * @returns {String} The token in JWT format. */ generateTenantToken( + apiKeyUid: string, searchRules: TokenSearchRules, options?: TokenOptions ): string { if (typeof window === 'undefined') { - return this.tokens.generateTenantToken(searchRules, options) + return this.tokens.generateTenantToken(apiKeyUid, searchRules, options) } - return super.generateTenantToken(searchRules, options) + return super.generateTenantToken(apiKeyUid, searchRules, options) } } export { MeiliSearch } diff --git a/src/http-requests.ts b/src/http-requests.ts index ade13bc67..3ef943fcd 100644 --- a/src/http-requests.ts +++ b/src/http-requests.ts @@ -1,6 +1,7 @@ import 'cross-fetch/polyfill' import { Config, EnqueuedTask } from './types' +import { PACKAGE_VERSION } from './package-version' import { MeiliSearchError, @@ -20,16 +21,46 @@ function constructHostURL(host: string): string { } } +function createHeaders(config: Config): Record { + const agentHeader = 'X-Meilisearch-Client' + const packageAgent = `Meilisearch JavaScript (v${PACKAGE_VERSION})` + const contentType = 'Content-Type' + config.headers = config.headers || {} + + const headers: Record = Object.assign({}, config.headers) // Create a hard copy and not a reference to config.headers + + if (config.apiKey) { + headers['Authorization'] = `Bearer ${config.apiKey}` + } + + if (!config.headers[contentType]) { + headers['Content-Type'] = 'application/json' + } + + // Creates the custom user agent with information on the package used. + if (config.clientAgents && Array.isArray(config.clientAgents)) { + const clients = config.clientAgents.concat(packageAgent) + + headers[agentHeader] = clients.join(' ; ') + } else if (config.clientAgents && !Array.isArray(config.clientAgents)) { + // If the header is defined but not an array + throw new MeiliSearchError( + `Meilisearch: The header "${agentHeader}" should be an array of string(s).\n` + ) + } else { + headers[agentHeader] = packageAgent + } + + return headers +} + class HttpRequests { headers: Record url: URL constructor(config: Config) { - this.headers = Object.assign({}, config.headers || {}) // assign to avoid referencing - this.headers['Content-Type'] = 'application/json' - if (config.apiKey) { - this.headers['Authorization'] = `Bearer ${config.apiKey}` - } + this.headers = createHeaders(config) + try { const host = constructHostURL(config.host) this.url = new URL(host) diff --git a/src/indexes.ts b/src/indexes.ts index 670eef4b3..31e45dca8 100644 --- a/src/indexes.ts +++ b/src/indexes.ts @@ -16,13 +16,13 @@ import { SearchParams, Filter, SearchRequestGET, - IndexResponse, + IndexObject, IndexOptions, IndexStats, - GetDocumentsParams, - GetDocumentsResponse, + DocumentsQuery, + DocumentQuery, Document, - AddDocumentParams, + DocumentOptions, EnqueuedTask, Settings, Synonyms, @@ -34,7 +34,10 @@ import { SearchableAttributes, DisplayedAttributes, TypoTolerance, - Result, + WaitOptions, + DocumentsResults, + TasksQuery, + TasksResults, } from './types' import { removeUndefinedFromObject } from './utils' import { HttpRequests } from './http-requests' @@ -120,7 +123,7 @@ class Index> { ...options, filter: parseFilter(options?.filter), sort: options?.sort?.join(','), - facetsDistribution: options?.facetsDistribution?.join(','), + facets: options?.facets?.join(','), attributesToRetrieve: options?.attributesToRetrieve?.join(','), attributesToCrop: options?.attributesToCrop?.join(','), attributesToHighlight: options?.attributesToHighlight?.join(','), @@ -141,11 +144,12 @@ class Index> { * Get index information. * @memberof Index * @method getRawInfo - * @returns {Promise} Promise containing index information + * + * @returns {Promise} Promise containing index information */ - async getRawInfo(): Promise { + async getRawInfo(): Promise { const url = `indexes/${this.uid}` - const res = await this.httpRequest.get(url) + const res = await this.httpRequest.get(url) this.primaryKey = res.primaryKey this.updatedAt = new Date(res.updatedAt) this.createdAt = new Date(res.createdAt) @@ -203,7 +207,7 @@ class Index> { */ async update(data: IndexOptions): Promise { const url = `indexes/${this.uid}` - return await this.httpRequest.put(url, data) + return await this.httpRequest.patch(url, data) } /** @@ -222,15 +226,16 @@ class Index> { /// /** - * Get the list of all the index tasks. + * Get the list of all the tasks of the index. * * @memberof Indexes * @method getTasks + * @param {TasksQuery} [parameters={}] - Parameters to browse the tasks * - * @returns {Promise>} - Promise containing all tasks + * @returns {Promise} - Promise containing all tasks */ - async getTasks(): Promise> { - return await this.tasks.getIndexTasks(this.uid) + async getTasks(parameters: TasksQuery = {}): Promise { + return await this.tasks.getTasks({ ...parameters, indexUid: [this.uid] }) } /** @@ -238,55 +243,49 @@ class Index> { * * @memberof Indexes * @method getTask - * @param {number} taskId - Task identifier + * @param {number} taskUid - Task identifier * * @returns {Promise} - Promise containing a task */ - async getTask(taskId: number): Promise { - return await this.tasks.getIndexTask(this.uid, taskId) + async getTask(taskUid: number): Promise { + return await this.tasks.getTask(taskUid) } /** - * Wait for a batch of an index tasks to be processed. + * Wait for multiple tasks to be processed. * * @memberof Indexes * @method waitForTasks - * @param {number[]} taskIds - Tasks identifier + * @param {number[]} taskUids - Tasks identifier * @param {WaitOptions} waitOptions - Options on timeout and interval * - * @returns {Promise>} - Promise containing an array of tasks + * @returns {Promise} - Promise containing an array of tasks */ async waitForTasks( - taskIds: number[], - { - timeOutMs = 5000, - intervalMs = 50, - }: { timeOutMs?: number; intervalMs?: number } = {} - ): Promise> { - return await this.tasks.waitForClientTasks(taskIds, { + taskUids: number[], + { timeOutMs = 5000, intervalMs = 50 }: WaitOptions = {} + ): Promise { + return await this.tasks.waitForTasks(taskUids, { timeOutMs, intervalMs, }) } /** - * Wait for an index task to be processed. + * Wait for a task to be processed. * * @memberof Indexes * @method waitForTask - * @param {number} taskId - Task identifier + * @param {number} taskUid - Task identifier * @param {WaitOptions} waitOptions - Options on timeout and interval * * @returns {Promise} - Promise containing an array of tasks */ async waitForTask( - taskId: number, - { - timeOutMs = 5000, - intervalMs = 50, - }: { timeOutMs?: number; intervalMs?: number } = {} + taskUid: number, + { timeOutMs = 5000, intervalMs = 50 }: WaitOptions = {} ): Promise { - return await this.tasks.waitForClientTask(taskId, { + return await this.tasks.waitForTask(taskUid, { timeOutMs, intervalMs, }) @@ -315,22 +314,28 @@ class Index> { * @memberof Index * @method getDocuments * @template T - * @param {GetDocumentsParams} options? Options to browse the documents - * @returns {Promise>} Promise containing Document responses + * @param {DocumentsQuery} [parameters={}] Parameters to browse the documents + * @returns {Promise>>} Promise containing Document responses */ async getDocuments>( - options?: GetDocumentsParams - ): Promise> { + parameters: DocumentsQuery = {} + ): Promise> { const url = `indexes/${this.uid}/documents` - let attr - if (options !== undefined && Array.isArray(options.attributesToRetrieve)) { - attr = options.attributesToRetrieve.join(',') - } - return await this.httpRequest.get>(url, { - ...options, - ...(attr !== undefined ? { attributesToRetrieve: attr } : {}), - }) + const fields = (() => { + if (Array.isArray(parameters?.fields)) { + return parameters?.fields?.join(',') + } + return undefined + })() + + return await this.httpRequest.get>>( + url, + removeUndefinedFromObject({ + ...parameters, + fields, + }) + ) } /** @@ -339,11 +344,29 @@ class Index> { * @method getDocument * @template T * @param {string | number} documentId Document ID + * @param {DocumentQuery} [parameters={}] Parameters applied on a document * @returns {Promise>} Promise containing Document response */ - async getDocument(documentId: string | number): Promise> { + async getDocument>( + documentId: string | number, + parameters?: DocumentQuery + ): Promise> { const url = `indexes/${this.uid}/documents/${documentId}` - return await this.httpRequest.get>(url) + + const fields = (() => { + if (Array.isArray(parameters?.fields)) { + return parameters?.fields?.join(',') + } + return undefined + })() + + return await this.httpRequest.get>( + url, + removeUndefinedFromObject({ + ...parameters, + fields, + }) + ) } /** @@ -352,12 +375,13 @@ class Index> { * @method addDocuments * @template T * @param {Array>} documents Array of Document objects to add/replace - * @param {AddDocumentParams} options? Query parameters + * @param {DocumentOptions} options? Options on document addition + * * @returns {Promise} Promise containing object of the enqueued task */ async addDocuments( documents: Array>, - options?: AddDocumentParams + options?: DocumentOptions ): Promise { const url = `indexes/${this.uid}/documents` return await this.httpRequest.post(url, documents, options) @@ -370,13 +394,13 @@ class Index> { * @template T * @param {Array>} documents Array of Document objects to add/replace * @param {number} batchSize Size of the batch - * @param {AddDocumentParams} options? Query parameters + * @param {DocumentOptions} options? Options on document addition * @returns {Promise} Promise containing array of enqueued task objects for each batch */ async addDocumentsInBatches( documents: Array>, batchSize = 1000, - options?: AddDocumentParams + options?: DocumentOptions ): Promise { const updates = [] for (let i = 0; i < documents.length; i += batchSize) { @@ -392,12 +416,12 @@ class Index> { * @memberof Index * @method updateDocuments * @param {Array>>} documents Array of Document objects to add/update - * @param {AddDocumentParams} options? Query parameters + * @param {DocumentOptions} options? Options on document update * @returns {Promise} Promise containing object of the enqueued task */ async updateDocuments( documents: Array>>, - options?: AddDocumentParams + options?: DocumentOptions ): Promise { const url = `indexes/${this.uid}/documents` return await this.httpRequest.put(url, documents, options) @@ -410,13 +434,13 @@ class Index> { * @template T * @param {Array>} documents Array of Document objects to add/update * @param {number} batchSize Size of the batch - * @param {AddDocumentParams} options? Query parameters + * @param {DocumentOptions} options? Options on document update * @returns {Promise} Promise containing array of enqueued task objects for each batch */ async updateDocumentsInBatches( documents: Array>>, batchSize = 1000, - options?: AddDocumentParams + options?: DocumentOptions ): Promise { const updates = [] for (let i = 0; i < documents.length; i += batchSize) { @@ -490,7 +514,7 @@ class Index> { */ async updateSettings(settings: Settings): Promise { const url = `indexes/${this.uid}/settings` - return await this.httpRequest.post(url, settings) + return await this.httpRequest.patch(url, settings) } /** @@ -528,7 +552,7 @@ class Index> { */ async updateSynonyms(synonyms: Synonyms): Promise { const url = `indexes/${this.uid}/settings/synonyms` - return await this.httpRequest.post(url, synonyms) + return await this.httpRequest.put(url, synonyms) } /** @@ -566,7 +590,7 @@ class Index> { */ async updateStopWords(stopWords: StopWords): Promise { const url = `indexes/${this.uid}/settings/stop-words` - return await this.httpRequest.post(url, stopWords) + return await this.httpRequest.put(url, stopWords) } /** @@ -604,7 +628,7 @@ class Index> { */ async updateRankingRules(rankingRules: RankingRules): Promise { const url = `indexes/${this.uid}/settings/ranking-rules` - return await this.httpRequest.post(url, rankingRules) + return await this.httpRequest.put(url, rankingRules) } /** @@ -644,7 +668,7 @@ class Index> { distinctAttribute: DistinctAttribute ): Promise { const url = `indexes/${this.uid}/settings/distinct-attribute` - return await this.httpRequest.post(url, distinctAttribute) + return await this.httpRequest.put(url, distinctAttribute) } /** @@ -684,7 +708,7 @@ class Index> { filterableAttributes: FilterableAttributes ): Promise { const url = `indexes/${this.uid}/settings/filterable-attributes` - return await this.httpRequest.post(url, filterableAttributes) + return await this.httpRequest.put(url, filterableAttributes) } /** @@ -724,7 +748,7 @@ class Index> { sortableAttributes: SortableAttributes ): Promise { const url = `indexes/${this.uid}/settings/sortable-attributes` - return await this.httpRequest.post(url, sortableAttributes) + return await this.httpRequest.put(url, sortableAttributes) } /** @@ -764,7 +788,7 @@ class Index> { searchableAttributes: SearchableAttributes ): Promise { const url = `indexes/${this.uid}/settings/searchable-attributes` - return await this.httpRequest.post(url, searchableAttributes) + return await this.httpRequest.put(url, searchableAttributes) } /** @@ -804,7 +828,7 @@ class Index> { displayedAttributes: DisplayedAttributes ): Promise { const url = `indexes/${this.uid}/settings/displayed-attributes` - return await this.httpRequest.post(url, displayedAttributes) + return await this.httpRequest.put(url, displayedAttributes) } /** @@ -844,7 +868,7 @@ class Index> { typoTolerance: TypoTolerance ): Promise { const url = `indexes/${this.uid}/settings/typo-tolerance` - return await this.httpRequest.post(url, typoTolerance) + return await this.httpRequest.patch(url, typoTolerance) } /** diff --git a/src/package-version.ts b/src/package-version.ts new file mode 100644 index 000000000..735307a25 --- /dev/null +++ b/src/package-version.ts @@ -0,0 +1 @@ +export const PACKAGE_VERSION = '0.26.0' diff --git a/src/task.ts b/src/task.ts index 0b529b770..8fe98cddf 100644 --- a/src/task.ts +++ b/src/task.ts @@ -1,7 +1,14 @@ import { MeiliSearchTimeOutError } from './errors' -import { Config, Task, WaitOptions, TaskStatus, Result } from './types' +import { + Config, + Task, + WaitOptions, + TaskStatus, + TasksQuery, + TasksResults, +} from './types' import { HttpRequests } from './http-requests' -import { sleep } from './utils' +import { removeUndefinedFromObject, sleep } from './utils' class TaskClient { httpRequest: HttpRequests @@ -10,40 +17,57 @@ class TaskClient { this.httpRequest = new HttpRequests(config) } - async getClientTask(uid: string | number): Promise { + /** + * Get one task + * + * @param {number} uid - unique identifier of the task + * + * @returns { Promise } + */ + async getTask(uid: number): Promise { const url = `tasks/${uid}` return await this.httpRequest.get(url) } - async getClientTasks(): Promise> { + /** + * Get tasks + * + * @param {TasksQuery} [parameters={}] - Parameters to browse the tasks + * + * @returns {Promise} - Promise containing all tasks + */ + async getTasks(parameters: TasksQuery = {}): Promise { const url = `tasks` - return await this.httpRequest.get>(url) - } - async getIndexTask(indexUid: string | number, taskId: number): Promise { - const url = `indexes/${indexUid}/tasks/${taskId}` - return await this.httpRequest.get(url) - } + const queryParams = { + indexUid: parameters?.indexUid?.join(','), + type: parameters?.type?.join(','), + status: parameters?.status?.join(','), + from: parameters.from, + limit: parameters.limit, + } - async getIndexTasks(indexUid: string | number): Promise> { - const url = `indexes/${indexUid}/tasks` - return await this.httpRequest.get>(url) + return await this.httpRequest.get>( + url, + removeUndefinedFromObject(queryParams) + ) } /** * Wait for a task to be processed. * - * @param {number} uid Task identifier + * @param {number} taskUid Task identifier * @param {WaitOptions} options Additional configuration options + * * @returns {Promise} Promise returning a task after it has been processed */ - async waitForClientTask( - taskId: number, + async waitForTask( + taskUid: number, { timeOutMs = 5000, intervalMs = 50 }: WaitOptions = {} ): Promise { const startingTime = Date.now() while (Date.now() - startingTime < timeOutMs) { - const response = await this.getClientTask(taskId) + const response = await this.getTask(taskUid) if ( ![TaskStatus.TASK_ENQUEUED, TaskStatus.TASK_PROCESSING].includes( response.status @@ -53,58 +77,31 @@ class TaskClient { await sleep(intervalMs) } throw new MeiliSearchTimeOutError( - `timeout of ${timeOutMs}ms has exceeded on process ${taskId} when waiting a task to be resolved.` + `timeout of ${timeOutMs}ms has exceeded on process ${taskUid} when waiting a task to be resolved.` ) } /** * Waits for multiple tasks to be processed * - * @param {number} taskIds Tasks identifier list + * @param {number[]} taskUids Tasks identifier list * @param {WaitOptions} options Wait options - * @returns {Promise>} Promise returning a list of tasks after they have been processed + * + * @returns {Promise} Promise returning a list of tasks after they have been processed */ - async waitForClientTasks( - taskIds: number[], + async waitForTasks( + taskUids: number[], { timeOutMs = 5000, intervalMs = 50 }: WaitOptions = {} - ): Promise> { + ): Promise { const tasks: Task[] = [] - for (const taskId of taskIds) { - const task = await this.waitForClientTask(taskId, { + for (const taskUid of taskUids) { + const task = await this.waitForTask(taskUid, { timeOutMs, intervalMs, }) tasks.push(task) } - return { results: tasks } - } - - /** - * Waits for a task to be processed - * - * @param {number} taskId Task identifier - * @param {WaitOptions} options Wait options - * @returns {Promise} Promise returning a task after it has been processed - */ - async waitForIndexTask( - indexUid: number | string, - taskId: number, - { timeOutMs = 5000, intervalMs = 50 }: WaitOptions = {} - ): Promise { - const startingTime = Date.now() - while (Date.now() - startingTime < timeOutMs) { - const response = await this.getIndexTask(indexUid, taskId) - if ( - ![TaskStatus.TASK_ENQUEUED, TaskStatus.TASK_PROCESSING].includes( - response.status - ) - ) - return response - await sleep(intervalMs) - } - throw new MeiliSearchTimeOutError( - `timeout of ${timeOutMs}ms has exceeded on process ${taskId} when waiting for pending update to resolve.` - ) + return tasks } } diff --git a/src/token.ts b/src/token.ts index 3861188f7..d3ffd8b60 100644 --- a/src/token.ts +++ b/src/token.ts @@ -1,5 +1,7 @@ import { Config, TokenSearchRules, TokenOptions } from './types' import crypto from 'crypto' +import { MeiliSearchError } from './errors' +import { validateUuid4 } from './utils' function encode64(data: any) { return Buffer.from(JSON.stringify(data)).toString('base64') @@ -42,35 +44,52 @@ function createHeader() { * * @param {SearchRules} searchRules Search rules that are applied to every search. * @param {String} apiKey Api key used as issuer of the token. + * @param {String} uid The uid of the api key used as issuer of the token. * @param {Date | undefined} expiresAt Date at which the token expires. */ -function validatePayload(payloadParams: { +function validateTokenParameters(tokenParams: { searchRules: TokenSearchRules + uid: string apiKey: string expiresAt?: Date }) { - const { searchRules, apiKey, expiresAt } = payloadParams - const error = new Error() + const { searchRules, uid, apiKey, expiresAt } = tokenParams if (expiresAt) { - if (!(expiresAt instanceof Date) || expiresAt.getTime() < Date.now()) { - throw new Error( - `Meilisearch: When the expiresAt field in the token generation has a value, it must be a date set in the future and not in the past. \n ${error.stack}.` + if (!(expiresAt instanceof Date)) { + throw new MeiliSearchError( + `Meilisearch: The expiredAt field must be an instance of Date.` + ) + } else if (expiresAt.getTime() < Date.now()) { + throw new MeiliSearchError( + `Meilisearch: The expiresAt field must be a date in the future.` ) } } if (searchRules) { if (!(typeof searchRules === 'object' || Array.isArray(searchRules))) { - throw new Error( - `Meilisearch: The search rules added in the token generation must be of type array or object. \n ${error.stack}.` + throw new MeiliSearchError( + `Meilisearch: The search rules added in the token generation must be of type array or object.` ) } } if (!apiKey || typeof apiKey !== 'string') { - throw new Error( - `Meilisearch: The API key used for the token generation must exist and be of type string. \n ${error.stack}.` + throw new MeiliSearchError( + `Meilisearch: The API key used for the token generation must exist and be of type string.` + ) + } + + if (!uid || typeof uid !== 'string') { + throw new MeiliSearchError( + `Meilisearch: The uid of the api key used for the token generation must exist, be of type string and comply to the uuid4 format.` + ) + } + + if (!validateUuid4(uid)) { + throw new MeiliSearchError( + `Meilisearch: The uid of your key is not a valid uuid4. To find out the uid of your key use getKey().` ) } } @@ -79,20 +98,20 @@ function validatePayload(payloadParams: { * Create the payload of the token. * * @param {SearchRules} searchRules Search rules that are applied to every search. - * @param {String} apiKey Api key used as issuer of the token. + * @param {String} uid The uid of the api key used as issuer of the token. * @param {Date | undefined} expiresAt Date at which the token expires. * @returns {String} The payload encoded in base64. */ function createPayload(payloadParams: { searchRules: TokenSearchRules - apiKey: string + uid: string expiresAt?: Date }): string { - const { searchRules, apiKey, expiresAt } = payloadParams - validatePayload(payloadParams) + const { searchRules, uid, expiresAt } = payloadParams + const payload = { searchRules, - apiKeyPrefix: apiKey.substring(0, 8), + apiKeyUid: uid, exp: expiresAt?.getTime(), } @@ -111,19 +130,25 @@ class Token { * * @memberof MeiliSearch * @method generateTenantToken + * @param {apiKeyUid} apiKeyUid The uid of the api key used as issuer of the token. * @param {SearchRules} searchRules Search rules that are applied to every search. * @param {TokenOptions} options Token options to customize some aspect of the token. + * * @returns {String} The token in JWT format. */ generateTenantToken( + apiKeyUid: string, searchRules: TokenSearchRules, options?: TokenOptions ): string { const apiKey = options?.apiKey || this.config.apiKey || '' + const uid = apiKeyUid || '' const expiresAt = options?.expiresAt + validateTokenParameters({ apiKey, uid, expiresAt, searchRules }) + const encodedHeader = createHeader() - const encodedPayload = createPayload({ searchRules, apiKey, expiresAt }) + const encodedPayload = createPayload({ searchRules, uid, expiresAt }) const signature = sign(apiKey, encodedHeader, encodedPayload) return `${encodedHeader}.${encodedPayload}.${signature}` diff --git a/src/types/types.ts b/src/types/types.ts index 0c9e75310..1dbd7a84b 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -7,37 +7,44 @@ export type Config = { host: string apiKey?: string - headers?: object + clientAgents?: string[] + headers?: Record } -export type Result = { +/// +/// Resources +/// + +export type Pagination = { + offset?: number + limit?: number +} + +export type ResourceQuery = Pagination & {} + +export type ResourceResults = Pagination & { results: T + total: number } /// -/// Request specific interfaces +/// Indexes /// -export type IndexRequest = { - uid: string - primaryKey?: string -} - export type IndexOptions = { primaryKey?: string } -export type IndexResponse = { +export type IndexObject = { uid: string - name?: string primaryKey?: string createdAt: Date updatedAt: Date } -export type AddDocumentParams = { - primaryKey?: string -} +export type IndexesQuery = ResourceQuery & {} + +export type IndexesResults = ResourceResults & {} /* * SEARCH PARAMETERS @@ -45,11 +52,6 @@ export type AddDocumentParams = { export type Filter = string | Array -export type Pagination = { - offset?: number - limit?: number -} - export type Query = { q?: string | null } @@ -72,9 +74,9 @@ export type SearchParams = Query & Crop & { filter?: Filter sort?: string[] - facetsDistribution?: string[] + facets?: string[] attributesToRetrieve?: string[] - matches?: boolean + showMatchesPosition?: boolean } // Search parameters for searches made with the GET method @@ -85,11 +87,11 @@ export type SearchRequestGET = Pagination & Omit & { filter?: string sort?: string - facetsDistribution?: string + facets?: string attributesToRetrieve?: string attributesToHighlight?: string attributesToCrop?: string - matches?: boolean + showMatchesPosition?: boolean } export type CategoriesDistribution = { @@ -97,32 +99,26 @@ export type CategoriesDistribution = { } export type Facet = string -export type FacetsDistribution = Record -export type _matchesInfo = Partial< +export type FacetDistribution = Record +export type MatchesPosition = Partial< Record> > -export type document = { - [field: string]: any -} - -export type Hit = T & { +export type Hit> = T & { _formatted?: Partial - _matchesInfo?: _matchesInfo + _matchesPosition?: MatchesPosition } -export type Hits = Array> +export type Hits> = Array> export type SearchResponse> = { hits: Hits offset: number limit: number processingTimeMs: number - facetsDistribution?: FacetsDistribution - exhaustiveFacetsCount?: boolean + facetDistribution?: FacetDistribution query: string - nbHits: number - exhaustiveNbHits: boolean + estimatedTotalHits: number } export type FieldDistribution = { @@ -132,17 +128,29 @@ export type FieldDistribution = { /* ** Documents */ -export type GetDocumentsParams> = { - offset?: number - limit?: number - attributesToRetrieve?: - | Array> - | Extract + +type Fields> = + | Array> + | Extract + +export type DocumentOptions = { + primaryKey?: string +} + +export type DocumentsQuery> = ResourceQuery & { + fields?: Fields } -export type GetDocumentsResponse> = Array> +export type DocumentQuery> = { + fields?: Fields +} export type Document> = T +export type Documents> = Array> + +export type DocumentsResults> = ResourceResults< + Documents +> & {} /* ** Settings @@ -168,6 +176,13 @@ export type TypoTolerance = { } } | null +export type Faceting = { + maxValuesPerFacet?: number | null +} +export type PaginationSettings = { + maxTotalHits?: number | null +} + export type Settings = { filterableAttributes?: FilterableAttributes distinctAttribute?: DistinctAttribute @@ -178,6 +193,8 @@ export type Settings = { stopWords?: StopWords synonyms?: Synonyms typoTolerance?: TypoTolerance + faceting?: Faceting + pagination?: PaginationSettings } /* @@ -191,18 +208,34 @@ export const enum TaskStatus { TASK_ENQUEUED = 'enqueued', } +export const enum TaskTypes { + INDEX_CREATION = 'indexCreation', + INDEX_UPDATE = 'indexUpdate', + INDEX_DELETION = 'indexDeletion', + DOCUMENTS_ADDITION_OR_UPDATE = 'documentAdditionOrUpdate', + DOCUMENT_DELETION = 'documentDeletion', + SETTINGS_UPDATE = 'settingsUpdate', +} + +export type TasksQuery = { + indexUid?: string[] + type?: TaskTypes[] + status?: TaskStatus[] + limit?: number + from?: number +} + export type EnqueuedTask = { - uid: number - indexUid: string + taskUid: number + indexUid?: string status: TaskStatus - type: string + type: TaskTypes enqueuedAt: string } -export type Task = { - status: TaskStatus +export type Task = Omit & { uid: number - type: string + batchUid: number details: { // Number of documents sent receivedDocuments?: number @@ -240,19 +273,19 @@ export type Task = { // Distinct attribute on settings actions distinctAttribute: DistinctAttribute } - duration: string - enqueuedAt: string - processedAt: string error?: MeiliSearchErrorInfo -} - -export type EnqueuedDump = { - uid: string - status: 'in_progress' | 'failed' | 'done' + duration: string startedAt: string finishedAt: string } +export type TasksResults = { + results: Task[] + limit: number + from: number + next: number +} + export type WaitOptions = { timeOutMs?: number intervalMs?: number @@ -289,7 +322,9 @@ export type Stats = { */ export type Key = { + uid: string description: string + name: string | null key: string actions: string[] indexes: string[] @@ -298,13 +333,24 @@ export type Key = { updateAt: string } -export type KeyPayload = { +export type KeyCreation = { + uid?: string + name?: string description?: string actions: string[] indexes: string[] expiresAt: string | null } +export type KeyUpdate = { + name?: string + description?: string +} + +export type KeysQuery = ResourceQuery & {} + +export type KeysResults = ResourceResults & {} + /* ** version */ @@ -443,9 +489,6 @@ export const enum ErrorStatusCode { /** @see https://docs.meilisearch.com/errors/#task_not_found */ TASK_NOT_FOUND = 'task_not_found', - /** @see https://docs.meilisearch.com/errors/#dump_already_processing */ - DUMP_ALREADY_PROCESSING = 'dump_already_processing', - /** @see https://docs.meilisearch.com/errors/#dump_process_failed */ DUMP_PROCESS_FAILED = 'dump_process_failed', diff --git a/src/utils.ts b/src/utils.ts index 4da69326f..185bf0026 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -27,9 +27,15 @@ function addTrailingSlash(url: string): string { return url } +function validateUuid4(uuid: string): boolean { + const regexExp = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/gi + return regexExp.test(uuid) +} + export { sleep, removeUndefinedFromObject, addProtocolIfNotPresent, addTrailingSlash, + validateUuid4, } diff --git a/tests/client.test.ts b/tests/client.test.ts index 0d8b010c2..a9a0c294a 100644 --- a/tests/client.test.ts +++ b/tests/client.test.ts @@ -1,11 +1,5 @@ -import { - IndexResponse, - ErrorStatusCode, - Health, - Version, - Stats, - TaskStatus, -} from '../src' +import { ErrorStatusCode, Health, Version, Stats } from '../src' +import { PACKAGE_VERSION } from '../src/package-version' import { clearAllIndexes, getKey, @@ -173,19 +167,62 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( }) expect(client.config.headers).toStrictEqual({ Expect: '200-OK' }) const health = await client.isHealthy() + expect(health).toBe(true) - const status = await client.createIndex('test') - await client.waitForTask(status.uid) - const indexes = await client.getIndexes() - expect(indexes.length).toBe(1) + + const task = await client.createIndex('test') + await client.waitForTask(task.taskUid) + + const { results } = await client.getIndexes() + + expect(results.length).toBe(1) + }) + + test(`${permission} key: Create client with no custom client agents`, async () => { + const key = await getKey(permission) + const client = new MeiliSearch({ + ...config, + apiKey: key, + headers: {}, + }) + + expect(client.httpRequest.headers['X-Meilisearch-Client']).toStrictEqual( + `Meilisearch JavaScript (v${PACKAGE_VERSION})` + ) + }) + + test(`${permission} key: Create client with empty custom client agents`, async () => { + const key = await getKey(permission) + const client = new MeiliSearch({ + ...config, + apiKey: key, + clientAgents: [], + }) + + expect(client.httpRequest.headers['X-Meilisearch-Client']).toStrictEqual( + `Meilisearch JavaScript (v${PACKAGE_VERSION})` + ) + }) + + test(`${permission} key: Create client with custom client agents`, async () => { + const key = await getKey(permission) + const client = new MeiliSearch({ + ...config, + apiKey: key, + clientAgents: ['random plugin 1', 'random plugin 2'], + }) + + expect(client.httpRequest.headers['X-Meilisearch-Client']).toStrictEqual( + `random plugin 1 ; random plugin 2 ; Meilisearch JavaScript (v${PACKAGE_VERSION})` + ) }) describe('Test on indexes methods', () => { test(`${permission} key: create with no primary key`, async () => { const client = await getClient(permission) - const task = await client.createIndex(indexNoPk.uid) - await client.waitForTask(task.uid) + await client.waitForTask(task.taskUid) + const newIndex = await client.getIndex(indexNoPk.uid) expect(newIndex).toHaveProperty('uid', indexNoPk.uid) expect(newIndex).toHaveProperty('primaryKey', null) @@ -203,11 +240,11 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: create with primary key`, async () => { const client = await getClient(permission) - - const { uid } = await client.createIndex(indexPk.uid, { + const { taskUid } = await client.createIndex(indexPk.uid, { primaryKey: indexPk.primaryKey, }) - await client.waitForTask(uid) + await client.waitForTask(taskUid) + const newIndex = await client.getIndex(indexPk.uid) expect(newIndex).toHaveProperty('uid', indexPk.uid) @@ -226,11 +263,11 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: get all indexes when not empty`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexPk.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(indexPk.uid) + await client.waitForTask(taskUid) - const response: IndexResponse[] = await client.getRawIndexes() - const indexes = response.map((index) => index.uid) + const { results } = await client.getRawIndexes() + const indexes = results.map((index) => index.uid) expect(indexes).toEqual(expect.arrayContaining([indexPk.uid])) expect(indexes.length).toEqual(1) }) @@ -238,15 +275,17 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: Get index that exists`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexPk.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(indexPk.uid) + await client.waitForTask(taskUid) const response = await client.getIndex(indexPk.uid) + expect(response).toHaveProperty('uid', indexPk.uid) }) test(`${permission} key: Get index that does not exist`, async () => { const client = await getClient(permission) + await expect(client.getIndex('does_not_exist')).rejects.toHaveProperty( 'code', ErrorStatusCode.INDEX_NOT_FOUND @@ -255,10 +294,9 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: update primary key`, async () => { const client = await getClient(permission) - const { uid: createTask } = await client.createIndex(indexPk.uid) + const { taskUid: createTask } = await client.createIndex(indexPk.uid) await client.waitForTask(createTask) - - const { uid: updateTask } = await client.updateIndex(indexPk.uid, { + const { taskUid: updateTask } = await client.updateIndex(indexPk.uid, { primaryKey: 'newPrimaryKey', }) await client.waitForTask(updateTask) @@ -271,12 +309,11 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: update primary key that already exists`, async () => { const client = await getClient(permission) - const { uid: createTask } = await client.createIndex(indexPk.uid, { + const { taskUid: createTask } = await client.createIndex(indexPk.uid, { primaryKey: indexPk.primaryKey, }) await client.waitForTask(createTask) - - const { uid: updateTask } = await client.updateIndex(indexPk.uid, { + const { taskUid: updateTask } = await client.updateIndex(indexPk.uid, { primaryKey: 'newPrimaryKey', }) await client.waitForTask(updateTask) @@ -289,31 +326,34 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: delete index`, async () => { const client = await getClient(permission) - const { uid: createTask } = await client.createIndex(indexNoPk.uid) + const { taskUid: createTask } = await client.createIndex(indexNoPk.uid) await client.waitForTask(createTask) - const { uid: deleteTask } = await client.deleteIndex(indexNoPk.uid) - const task = await client.waitForTask(deleteTask) - expect(task.status).toBe(TaskStatus.TASK_SUCCEEDED) + const { taskUid: deleteTask } = await client.deleteIndex(indexNoPk.uid) + await client.waitForTask(deleteTask) + const { results } = await client.getIndexes() - await expect(client.getIndexes()).resolves.toHaveLength(0) + expect(results).toHaveLength(0) }) test(`${permission} key: create index with already existing uid should fail`, async () => { const client = await getClient(permission) - const { uid: firstCreate } = await client.createIndex(indexPk.uid) + const { taskUid: firstCreate } = await client.createIndex(indexPk.uid) await client.waitForTask(firstCreate) - const { uid: secondCreate } = await client.createIndex(indexPk.uid) + const { taskUid: secondCreate } = await client.createIndex(indexPk.uid) const task = await client.waitForTask(secondCreate) + expect(task.status).toBe('failed') }) test(`${permission} key: delete index with uid that does not exist should fail`, async () => { const client = await getClient(permission) const index = client.index(indexNoPk.uid) - const { uid } = await index.delete() - const task = await client.waitForTask(uid) + const { taskUid } = await index.delete() + + const task = await client.waitForTask(taskUid) + expect(task.status).toEqual('failed') }) @@ -444,22 +484,6 @@ describe.each([{ permission: 'Public' }])( ErrorStatusCode.INVALID_API_KEY ) }) - - test(`${permission} key: try to create dumps and be denir`, async () => { - const client = await getClient(permission) - await expect(client.createDump()).rejects.toHaveProperty( - 'code', - ErrorStatusCode.INVALID_API_KEY - ) - }) - - test(`${permission} key: try to create dumps and be denied`, async () => { - const client = await getClient(permission) - await expect(client.getDumpStatus('test')).rejects.toHaveProperty( - 'code', - ErrorStatusCode.INVALID_API_KEY - ) - }) }) } ) @@ -546,22 +570,6 @@ describe.each([{ permission: 'No' }])( ErrorStatusCode.MISSING_AUTHORIZATION_HEADER ) }) - - test(`${permission} key: try to create dumps and be denir`, async () => { - const client = await getClient(permission) - await expect(client.createDump()).rejects.toHaveProperty( - 'code', - ErrorStatusCode.MISSING_AUTHORIZATION_HEADER - ) - }) - - test(`${permission} key: try to create dumps and be denied`, async () => { - const client = await getClient(permission) - await expect(client.getDumpStatus('test')).rejects.toHaveProperty( - 'code', - ErrorStatusCode.MISSING_AUTHORIZATION_HEADER - ) - }) }) } ) @@ -687,30 +695,4 @@ describe.each([ )}` ) }) - - test(`Test createDump route`, async () => { - const route = `dumps` - const client = new MeiliSearch({ host }) - const strippedHost = trailing ? host.slice(0, -1) : host - await expect(client.createDump()).rejects.toHaveProperty( - 'message', - `request to ${strippedHost}/${route} failed, reason: connect ECONNREFUSED ${BAD_HOST.replace( - 'http://', - '' - )}` - ) - }) - - test(`Test getDumpStatus route`, async () => { - const route = `dumps/1/status` - const client = new MeiliSearch({ host }) - const strippedHost = trailing ? host.slice(0, -1) : host - await expect(client.getDumpStatus('1')).rejects.toHaveProperty( - 'message', - `request to ${strippedHost}/${route} failed, reason: connect ECONNREFUSED ${BAD_HOST.replace( - 'http://', - '' - )}` - ) - }) }) diff --git a/tests/displayed_attributes.test.ts b/tests/displayed_attributes.test.ts index 4d43b1369..3e88595b9 100644 --- a/tests/displayed_attributes.test.ts +++ b/tests/displayed_attributes.test.ts @@ -1,4 +1,4 @@ -import { EnqueuedTask, ErrorStatusCode } from '../src/types' +import { ErrorStatusCode } from '../src/types' import { clearAllIndexes, config, @@ -24,8 +24,8 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( beforeEach(async () => { await clearAllIndexes(config) const client = await getClient('Master') - const { uid } = await client.index(index.uid).addDocuments(dataset) - await client.waitForTask(uid) + const { taskUid } = await client.index(index.uid).addDocuments(dataset) + await client.waitForTask(taskUid) }) test(`${permission} key: Get default displayed attributes`, async () => { @@ -37,47 +37,36 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: Update displayed attributes`, async () => { const client = await getClient(permission) - const newDisplayedAttribute = ['title'] - const task: EnqueuedTask = await client + const task = await client .index(index.uid) .updateDisplayedAttributes(newDisplayedAttribute) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + await client.index(index.uid).waitForTask(task.taskUid) + + const response = await client.index(index.uid).getDisplayedAttributes() - const response: string[] = await client - .index(index.uid) - .getDisplayedAttributes() expect(response).toEqual(newDisplayedAttribute) }) test(`${permission} key: Update displayed attributes at null`, async () => { const client = await getClient(permission) - const task: EnqueuedTask = await client - .index(index.uid) - .updateDisplayedAttributes(null) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + const task = await client.index(index.uid).updateDisplayedAttributes(null) + await client.index(index.uid).waitForTask(task.taskUid) + + const response = await client.index(index.uid).getDisplayedAttributes() - const response: string[] = await client - .index(index.uid) - .getDisplayedAttributes() expect(response).toEqual(['*']) }) test(`${permission} key: Reset displayed attributes`, async () => { const client = await getClient(permission) - const task: EnqueuedTask = await client - .index(index.uid) - .resetDisplayedAttributes() - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + const task = await client.index(index.uid).resetDisplayedAttributes() + await client.index(index.uid).waitForTask(task.taskUid) + + const response = await client.index(index.uid).getDisplayedAttributes() - const response: string[] = await client - .index(index.uid) - .getDisplayedAttributes() expect(response).toEqual(['*']) }) } @@ -89,8 +78,8 @@ describe.each([{ permission: 'Public' }])( beforeEach(async () => { await clearAllIndexes(config) const client = await getClient('Master') - const { uid } = await client.createIndex(index.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(index.uid) + await client.waitForTask(taskUid) }) test(`${permission} key: try to get displayed attributes and be denied`, async () => { @@ -122,8 +111,8 @@ describe.each([{ permission: 'No' }])( beforeEach(async () => { await clearAllIndexes(config) const client = await getClient('Master') - const { uid } = await client.createIndex(index.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(index.uid) + await client.waitForTask(taskUid) }) test(`${permission} key: try to get displayed attributes and be denied`, async () => { diff --git a/tests/distinct_attribute.test.ts b/tests/distinct_attribute.test.ts index 010117b51..83e955a41 100644 --- a/tests/distinct_attribute.test.ts +++ b/tests/distinct_attribute.test.ts @@ -1,4 +1,4 @@ -import { EnqueuedTask, ErrorStatusCode } from '../src/types' +import { ErrorStatusCode } from '../src/types' import { clearAllIndexes, config, @@ -25,58 +25,46 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( await clearAllIndexes(config) const client = await getClient('master') - const { uid } = await client.index(index.uid).addDocuments(dataset) - await client.waitForTask(uid) + const { taskUid } = await client.index(index.uid).addDocuments(dataset) + await client.waitForTask(taskUid) }) test(`${permission} key: Get default distinct attribute`, async () => { const client = await getClient(permission) - const response: string | null = await client - .index(index.uid) - .getDistinctAttribute() + const response = await client.index(index.uid).getDistinctAttribute() expect(response).toEqual(null) }) test(`${permission} key: Update distinct attribute`, async () => { const client = await getClient(permission) const newDistinctAttribute = 'title' - const task: EnqueuedTask = await client + const task = await client .index(index.uid) .updateDistinctAttribute(newDistinctAttribute) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + await client.index(index.uid).waitForTask(task.taskUid) + + const response = await client.index(index.uid).getDistinctAttribute() - const response: string | null = await client - .index(index.uid) - .getDistinctAttribute() expect(response).toEqual(newDistinctAttribute) }) test(`${permission} key: Update distinct attribute at null`, async () => { const client = await getClient(permission) - const task: EnqueuedTask = await client - .index(index.uid) - .updateDistinctAttribute(null) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + const task = await client.index(index.uid).updateDistinctAttribute(null) + await client.index(index.uid).waitForTask(task.taskUid) + + const response = await client.index(index.uid).getDistinctAttribute() - const response: string | null = await client - .index(index.uid) - .getDistinctAttribute() expect(response).toEqual(null) }) test(`${permission} key: Reset distinct attribute`, async () => { const client = await getClient(permission) - const task: EnqueuedTask = await client - .index(index.uid) - .resetDistinctAttribute() - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + const task = await client.index(index.uid).resetDistinctAttribute() + await client.index(index.uid).waitForTask(task.taskUid) + + const response = await client.index(index.uid).getDistinctAttribute() - const response: string | null = await client - .index(index.uid) - .getDistinctAttribute() expect(response).toEqual(null) }) } diff --git a/tests/documents.test.ts b/tests/documents.test.ts index 307438095..16ff2a05f 100644 --- a/tests/documents.test.ts +++ b/tests/documents.test.ts @@ -1,9 +1,4 @@ -import { - ErrorStatusCode, - EnqueuedTask, - IndexResponse, - TaskStatus, -} from '../src/types' +import { ErrorStatusCode, TaskStatus, TaskTypes } from '../src/types' import { clearAllIndexes, config, @@ -35,11 +30,11 @@ describe('Documents tests', () => { beforeEach(async () => { await clearAllIndexes(config) const client = await getClient('Master') - - const { uid: taskCreateNoPk } = await client.createIndex(indexNoPk.uid) + const { taskUid: taskCreateNoPk } = await client.createIndex( + indexNoPk.uid + ) await client.waitForTask(taskCreateNoPk) - - const { uid: taskCreateWithPk } = await client.createIndex( + const { taskUid: taskCreateWithPk } = await client.createIndex( indexPk.uid, { primaryKey: indexPk.primaryKey, @@ -48,92 +43,143 @@ describe('Documents tests', () => { await client.waitForTask(taskCreateWithPk) }) - test(`${permission} key: Add documents to uid with NO primary key`, async () => { - const client = await getClient(permission) - const response = await client.index(indexNoPk.uid).addDocuments(dataset) - expect(response).toHaveProperty('uid', expect.any(Number)) - await client.index(indexNoPk.uid).waitForTask(response.uid) - }) - - test(`${permission} key: Add documents to uid with primary key`, async () => { - const client = await getClient(permission) - const response = await client.index(indexPk.uid).addDocuments(dataset) - expect(response).toHaveProperty('uid', expect.any(Number)) - await client.index(indexPk.uid).waitForTask(response.uid) - }) - test(`${permission} key: Add documents to uid with primary key in batch`, async () => { const client = await getClient(permission) const tasks = await client .index(indexPk.uid) .addDocumentsInBatches(dataset, 4) - expect(tasks).toBeInstanceOf(Array) expect(tasks).toHaveLength(2) - expect(tasks[0]).toHaveProperty('uid', expect.any(Number)) for (const task of tasks) { - const { type, status } = await client.waitForTask(task.uid) + const { type, status } = await client.waitForTask(task.taskUid) expect(status).toBe(TaskStatus.TASK_SUCCEEDED) - expect(type).toBe('documentAddition') + expect(type).toBe(TaskTypes.DOCUMENTS_ADDITION_OR_UPDATE) } }) - test(`${permission} key: Get documents with string attributesToRetrieve`, async () => { + test(`${permission} key: Get one document `, async () => { + const client = await getClient(permission) + const { taskUid } = await client + .index(indexNoPk.uid) + .addDocuments(dataset) + await client.index(indexNoPk.uid).waitForTask(taskUid) + + const documentId = 1 + const document = await client + .index(indexNoPk.uid) + .getDocument(documentId) + + expect(document.title).toEqual('Alice In Wonderland') + }) + + test(`${permission} key: Get one document with fields parameter`, async () => { const client = await getClient(permission) - const response = await client.index(indexNoPk.uid).getDocuments({ - attributesToRetrieve: 'id', + const { taskUid } = await client + .index(indexNoPk.uid) + .addDocuments(dataset) + await client.index(indexNoPk.uid).waitForTask(taskUid) + + const documentId = 1 + const document = await client + .index(indexNoPk.uid) + .getDocument(documentId, { fields: ['title'] }) + + expect(document.title).toEqual('Alice In Wonderland') + expect(document.id).toBeUndefined() + }) + + test(`${permission} key: Get documents with string fields`, async () => { + const client = await getClient(permission) + + const documents = await client.index(indexNoPk.uid).getDocuments({ + fields: 'id', }) - expect(response.find((x) => Object.keys(x).length !== 1)).toEqual( - undefined - ) + + expect( + documents.results.find((x) => Object.keys(x).length !== 1) + ).toBeUndefined() }) - test(`${permission} key: Get documents with array attributesToRetrieve`, async () => { + test(`${permission} key: Get documents with array fields`, async () => { const client = await getClient(permission) - const response = await client.index(indexNoPk.uid).getDocuments({ - attributesToRetrieve: ['id'], + const { taskUid } = await client + .index(indexPk.uid) + .addDocuments(dataset) + await client.waitForTask(taskUid) + + const documents = await client.index(indexPk.uid).getDocuments({ + fields: ['id'], }) - expect(response.find((x) => Object.keys(x).length !== 1)).toEqual( - undefined + const onlyIdFields = Array.from( + new Set( + documents.results.reduce( + (acc, document) => [...acc, ...Object.keys(document)], + [] + ) + ) ) + + expect(onlyIdFields.length).toEqual(1) + expect(onlyIdFields[0]).toEqual('id') + }) + + test(`${permission} key: Get documents with pagination`, async () => { + const client = await getClient(permission) + const { taskUid } = await client + .index(indexPk.uid) + .addDocuments(dataset) + await client.waitForTask(taskUid) + + const documents = await client.index(indexPk.uid).getDocuments({ + limit: 1, + offset: 2, + }) + + expect(documents.results.length).toEqual(1) + expect(documents.limit).toEqual(1) + expect(documents.offset).toEqual(2) }) test(`${permission} key: Get documents from index that has NO primary key`, async () => { const client = await getClient(permission) - const { uid } = await client.index(indexNoPk.uid).addDocuments(dataset) - await client.index(indexNoPk.uid).waitForTask(uid) + const { taskUid } = await client + .index(indexNoPk.uid) + .addDocuments(dataset) + await client.index(indexNoPk.uid).waitForTask(taskUid) - const response = await client.index(indexNoPk.uid).getDocuments({ - attributesToRetrieve: 'id', + const documents = await client.index(indexNoPk.uid).getDocuments({ + fields: 'id', }) - expect(response.length).toEqual(dataset.length) + + expect(documents.results.length).toEqual(dataset.length) }) test(`${permission} key: Get documents from index that has a primary key`, async () => { const client = await getClient(permission) - const { uid } = await client.index(indexPk.uid).addDocuments(dataset) - await client.index(indexPk.uid).waitForTask(uid) + const { taskUid } = await client + .index(indexPk.uid) + .addDocuments(dataset) + await client.index(indexPk.uid).waitForTask(taskUid) - const response = await client.index(indexPk.uid).getDocuments() - expect(response.length).toEqual(dataset.length) + const documents = await client.index(indexPk.uid).getDocuments() + expect(documents.results.length).toEqual(dataset.length) }) test(`${permission} key: Replace documents from index that has NO primary key`, async () => { const client = await getClient(permission) - const { uid: addDocUpdate } = await client + const { taskUid: addDocTask } = await client .index(indexNoPk.uid) .addDocuments(dataset) - await client.index(indexNoPk.uid).waitForTask(addDocUpdate) - + await client.index(indexNoPk.uid).waitForTask(addDocTask) const id = 2 const title = 'The Red And The Black' - const documents: EnqueuedTask = await client + + const task = await client .index(indexNoPk.uid) .addDocuments([{ id, title }]) - expect(documents).toHaveProperty('uid', expect.any(Number)) - await client.index(indexNoPk.uid).waitForTask(documents.uid) - + await client.index(indexNoPk.uid).waitForTask(task.taskUid) const response = await client.index(indexNoPk.uid).getDocument(id) + expect(response).toHaveProperty('id', id) expect(response).toHaveProperty('title', title) }) @@ -142,13 +188,13 @@ describe('Documents tests', () => { const client = await getClient(permission) const id = 2 const title = 'The Red And The Black' - const documents: EnqueuedTask = await client + + const task = await client .index(indexPk.uid) .addDocuments([{ id, title }]) - expect(documents).toHaveProperty('uid', expect.any(Number)) - await client.index(indexPk.uid).waitForTask(documents.uid) - + await client.index(indexPk.uid).waitForTask(task.taskUid) const response = await client.index(indexPk.uid).getDocument(id) + expect(response).toHaveProperty('id', id) expect(response).toHaveProperty('title', title) }) @@ -158,13 +204,12 @@ describe('Documents tests', () => { const id = 456 const title = 'The Little Prince' - const documents: EnqueuedTask = await client + const task = await client .index(indexNoPk.uid) .updateDocuments([{ id, title }]) - expect(documents).toHaveProperty('uid', expect.any(Number)) - await client.index(indexNoPk.uid).waitForTask(documents.uid) - + await client.index(indexNoPk.uid).waitForTask(task.taskUid) const response = await client.index(indexNoPk.uid).getDocument(id) + expect(response).toHaveProperty('id', id) expect(response).toHaveProperty('title', title) }) @@ -173,13 +218,12 @@ describe('Documents tests', () => { const client = await getClient(permission) const id = 456 const title = 'The Little Prince' - const documents: EnqueuedTask = await client + const task = await client .index(indexPk.uid) .updateDocuments([{ id, title }]) - expect(documents).toHaveProperty('uid', expect.any(Number)) - await client.index(indexPk.uid).waitForTask(documents.uid) - + await client.index(indexPk.uid).waitForTask(task.taskUid) const response = await client.index(indexPk.uid).getDocument(id) + expect(response).toHaveProperty('id', id) expect(response).toHaveProperty('title', title) }) @@ -187,10 +231,10 @@ describe('Documents tests', () => { test(`${permission} key: Partial update of a document`, async () => { const client = await getClient(permission) const id = 456 - const documents: EnqueuedTask = await client + const task = await client .index(indexPk.uid) .updateDocuments([{ id }]) - await client.index(indexPk.uid).waitForTask(documents.uid) + await client.index(indexPk.uid).waitForTask(task.taskUid) const response = await client.index(indexPk.uid).getDocument(id) @@ -203,16 +247,15 @@ describe('Documents tests', () => { const tasks = await client .index(indexPk.uid) .updateDocumentsInBatches(dataset, 2) - expect(tasks).toBeInstanceOf(Array) - expect(tasks).toHaveLength(4) - expect(tasks[0]).toHaveProperty('uid', expect.any(Number)) + for (const EnqueuedTask of tasks) { const task = await client .index(indexPk.uid) - .waitForTask(EnqueuedTask.uid) + .waitForTask(EnqueuedTask.taskUid) expect(task.status).toBe(TaskStatus.TASK_SUCCEEDED) - expect(task.type).toBe('documentPartial') + expect(task.type).toBe(TaskTypes.DOCUMENTS_ADDITION_OR_UPDATE) } + expect(tasks).toHaveLength(4) }) test(`${permission} key: Partial update of a document in batch`, async () => { @@ -223,169 +266,142 @@ describe('Documents tests', () => { .index(indexPk.uid) .updateDocumentsInBatches([partialDocument], 2) - expect(tasks).toBeInstanceOf(Array) - expect(tasks).toHaveLength(1) - expect(tasks[0]).toHaveProperty('uid', expect.any(Number)) - for (const EnqueuedTask of tasks) { const task = await client .index(indexPk.uid) - .waitForTask(EnqueuedTask.uid) + .waitForTask(EnqueuedTask.taskUid) expect(task.status).toBe(TaskStatus.TASK_SUCCEEDED) - expect(task.type).toBe('documentPartial') + expect(task.type).toBe(TaskTypes.DOCUMENTS_ADDITION_OR_UPDATE) } + expect(tasks).toHaveLength(1) }) test(`${permission} key: Add document with update documents function from index that has NO primary key`, async () => { const client = await getClient(permission) - const { uid: addDocUpdate } = await client + const { taskUid: addDocTask } = await client .index(indexNoPk.uid) .addDocuments(dataset) - await client.index(indexNoPk.uid).waitForTask(addDocUpdate) - + await client.index(indexNoPk.uid).waitForTask(addDocTask) const id = 9 const title = '1984' - const documents: EnqueuedTask = await client + const task = await client .index(indexNoPk.uid) .updateDocuments([{ id, title }]) - expect(documents).toHaveProperty('uid', expect.any(Number)) - await client.index(indexNoPk.uid).waitForTask(documents.uid) - + await client.index(indexNoPk.uid).waitForTask(task.taskUid) const document = await client.index(indexNoPk.uid).getDocument(id) + const documents = await client.index(indexNoPk.uid).getDocuments() + expect(document).toHaveProperty('id', id) expect(document).toHaveProperty('title', title) - - const response = await client.index(indexNoPk.uid).getDocuments() - expect(response.length).toEqual(dataset.length + 1) + expect(documents.results.length).toEqual(dataset.length + 1) }) test(`${permission} key: Add document with update documents function from index that has a primary key`, async () => { const client = await getClient(permission) - const { uid: addDocUpdate } = await client + const { taskUid: addDocTask } = await client .index(indexPk.uid) .addDocuments(dataset) - await client.index(indexPk.uid).waitForTask(addDocUpdate) - + await client.index(indexPk.uid).waitForTask(addDocTask) const id = 9 const title = '1984' - const documents: EnqueuedTask = await client + const task = await client .index(indexPk.uid) .updateDocuments([{ id, title }]) - expect(documents).toHaveProperty('uid', expect.any(Number)) - await client.index(indexPk.uid).waitForTask(documents.uid) + await client.index(indexPk.uid).waitForTask(task.taskUid) const document = await client.index(indexPk.uid).getDocument(id) + const documents = await client.index(indexPk.uid).getDocuments() + expect(document).toHaveProperty('id', id) expect(document).toHaveProperty('title', title) - - const response = await client.index(indexPk.uid).getDocuments() - expect(response.length).toEqual(dataset.length + 1) + expect(documents.results.length).toEqual(dataset.length + 1) }) test(`${permission} key: Delete a document from index that has NO primary key`, async () => { const client = await getClient(permission) - const { uid: addDocUpdate } = await client + const { taskUid: addDocTask } = await client .index(indexNoPk.uid) .addDocuments(dataset) - await client.index(indexNoPk.uid).waitForTask(addDocUpdate) - + await client.index(indexNoPk.uid).waitForTask(addDocTask) const id = 9 - const document: EnqueuedTask = await client - .index(indexNoPk.uid) - .deleteDocument(id) - expect(document).toHaveProperty('uid', expect.any(Number)) - await client.index(indexNoPk.uid).waitForTask(document.uid) + const task = await client.index(indexNoPk.uid).deleteDocument(id) + await client.index(indexNoPk.uid).waitForTask(task.taskUid) + const documents = await client.index(indexNoPk.uid).getDocuments() - const response = await client.index(indexNoPk.uid).getDocuments() - expect(response.length).toEqual(dataset.length) + expect(documents.results.length).toEqual(dataset.length) }) test(`${permission} key: Delete a document from index that has a primary key`, async () => { const client = await getClient(permission) - const { uid: addDocUpdate } = await client + const { taskUid: addDocTask } = await client .index(indexPk.uid) .addDocuments(dataset) - await client.index(indexPk.uid).waitForTask(addDocUpdate) + await client.index(indexPk.uid).waitForTask(addDocTask) const id = 9 - const document: EnqueuedTask = await client - .index(indexPk.uid) - .deleteDocument(id) - expect(document).toHaveProperty('uid', expect.any(Number)) - await client.index(indexPk.uid).waitForTask(document.uid) + const task = await client.index(indexPk.uid).deleteDocument(id) + await client.index(indexPk.uid).waitForTask(task.taskUid) + const response = await client.index(indexPk.uid).getDocuments() - const response = await client.index(indexPk.uid).getDocuments() - expect(response.length).toEqual(dataset.length) + expect(response.results.length).toEqual(dataset.length) }) test(`${permission} key: Delete some documents from index that has NO primary key`, async () => { const client = await getClient(permission) - const { uid: addDocUpdate } = await client + const { taskUid: addDocTask } = await client .index(indexNoPk.uid) .addDocuments(dataset) - await client.index(indexNoPk.uid).waitForTask(addDocUpdate) + await client.index(indexNoPk.uid).waitForTask(addDocTask) const ids = [1, 2] + const task = await client.index(indexNoPk.uid).deleteDocuments(ids) + await client.index(indexNoPk.uid).waitForTask(task.taskUid) - const documents: EnqueuedTask = await client - .index(indexNoPk.uid) - .deleteDocuments(ids) - expect(documents).toHaveProperty('uid', expect.any(Number)) - await client.index(indexNoPk.uid).waitForTask(documents.uid) + const documents = await client.index(indexNoPk.uid).getDocuments() + const returnedIds = documents.results.map((x) => x.id) - const response = await client.index(indexNoPk.uid).getDocuments() - expect(response.length).toEqual(dataset.length - 2) - const returnedIds = response.map((x) => x.id) + expect(documents.results.length).toEqual(dataset.length - 2) expect(returnedIds).not.toContain(ids[0]) expect(returnedIds).not.toContain(ids[1]) }) test(`${permission} key: Delete some documents from index that has a primary key`, async () => { const client = await getClient(permission) - const { uid: addDocUpdate } = await client + const { taskUid: addDocTask } = await client .index(indexPk.uid) .addDocuments(dataset) - await client.index(indexPk.uid).waitForTask(addDocUpdate) + await client.index(indexPk.uid).waitForTask(addDocTask) const ids = [1, 2] - const documents: EnqueuedTask = await client - .index(indexPk.uid) - .deleteDocuments(ids) - expect(documents).toHaveProperty('uid', expect.any(Number)) - await client.index(indexPk.uid).waitForTask(documents.uid) + const task = await client.index(indexPk.uid).deleteDocuments(ids) + await client.index(indexPk.uid).waitForTask(task.taskUid) + const documents = await client.index(indexPk.uid).getDocuments() + const returnedIds = documents.results.map((x) => x.id) - const response = await client.index(indexPk.uid).getDocuments() - expect(response.length).toEqual(dataset.length - 2) - const returnedIds = response.map((x) => x.id) + expect(documents.results.length).toEqual(dataset.length - 2) expect(returnedIds).not.toContain(ids[0]) expect(returnedIds).not.toContain(ids[1]) }) test(`${permission} key: Delete all document from index that has NO primary key`, async () => { const client = await getClient(permission) - const documents: EnqueuedTask = await client - .index(indexNoPk.uid) - .deleteAllDocuments() - expect(documents).toHaveProperty('uid', expect.any(Number)) - await client.index(indexNoPk.uid).waitForTask(documents.uid) + const task = await client.index(indexNoPk.uid).deleteAllDocuments() + await client.index(indexNoPk.uid).waitForTask(task.taskUid) - const response = await client.index(indexNoPk.uid).getDocuments() - expect(response.length).toEqual(0) + const documents = await client.index(indexNoPk.uid).getDocuments() + expect(documents.results.length).toEqual(0) }) test(`${permission} key: Delete all document from index that has a primary key`, async () => { const client = await getClient(permission) - const documents: EnqueuedTask = await client - .index(indexPk.uid) - .deleteAllDocuments() - expect(documents).toHaveProperty('uid', expect.any(Number)) - await client.index(indexPk.uid).waitForTask(documents.uid) + const task = await client.index(indexPk.uid).deleteAllDocuments() + await client.index(indexPk.uid).waitForTask(task.taskUid) - const response = await client.index(indexPk.uid).getDocuments() - expect(response.length).toEqual(0) + const documents = await client.index(indexPk.uid).getDocuments() + expect(documents.results.length).toEqual(0) }) test(`${permission} key: Try to get deleted document from index that has NO primary key`, async () => { @@ -411,54 +427,49 @@ describe('Documents tests', () => { title: 'Le Rouge et le Noir', }, ] - const pkIndex = 'update_pk' - const { uid } = await client.createIndex(pkIndex) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(pkIndex) + await client.waitForTask(taskUid) - const index = await client.getIndex(pkIndex) - expect(index).toHaveProperty('uid', pkIndex) - - const task: EnqueuedTask = await client + const task = await client .index(pkIndex) .addDocuments(docs, { primaryKey: 'unique' }) + await client.waitForTask(task.taskUid) - expect(task).toHaveProperty('uid', expect.any(Number)) - - await client.waitForTask(task.uid) - - const response: IndexResponse = await client.index(pkIndex).getRawInfo() + const response = await client.index(pkIndex).getRawInfo() expect(response).toHaveProperty('uid', pkIndex) expect(response).toHaveProperty('primaryKey', 'unique') }) - test(`${permission} key: Add a document without a primary key and check response in update status`, async () => { + test(`${permission} key: Add a document without a primary key and check response in task status`, async () => { const client = await getClient(permission) const docs = [ { title: 'Le Rouge et le Noir', }, ] - const { uid } = await client.index(indexNoPk.uid).addDocuments(docs) - const { error } = await client.waitForTask(uid) + + const { taskUid } = await client.index(indexNoPk.uid).addDocuments(docs) + const { error } = await client.waitForTask(taskUid) + expect(error).toHaveProperty('code') expect(error).toHaveProperty('link') expect(error).toHaveProperty('message') expect(error).toHaveProperty('type') }) - test(`${permission} key: Try to add documents from index with no primary key with NO valid primary key, update should fail`, async () => { + test(`${permission} key: Try to add documents from index with no primary key with NO valid primary key, task should fail`, async () => { const client = await getClient(permission) - const { uid } = await client.index(indexNoPk.uid).addDocuments([ + const { taskUid } = await client.index(indexNoPk.uid).addDocuments([ { unique: 2, title: 'Le Rouge et le Noir', }, ]) - const task = await client.waitForTask(uid) - + const task = await client.waitForTask(taskUid) const index = await client.index(indexNoPk.uid).getRawInfo() + expect(index.uid).toEqual(indexNoPk.uid) expect(index.primaryKey).toEqual(null) expect(task.status).toEqual('failed') @@ -490,7 +501,7 @@ describe('Documents tests', () => { test(`${permission} key: Try to get documents and be denied`, async () => { const client = await getClient(permission) await expect( - client.index(indexPk.uid).getDocuments() + client.index(indexPk.uid).getDocuments() ).rejects.toHaveProperty('code', ErrorStatusCode.INVALID_API_KEY) }) @@ -547,7 +558,7 @@ describe('Documents tests', () => { test(`${permission} key: Try to get documents and be denied`, async () => { const client = await getClient(permission) await expect( - client.index(indexPk.uid).getDocuments() + client.index(indexPk.uid).getDocuments() ).rejects.toHaveProperty( 'code', ErrorStatusCode.MISSING_AUTHORIZATION_HEADER @@ -611,7 +622,7 @@ describe('Documents tests', () => { const client = new MeiliSearch({ host }) const strippedHost = trailing ? host.slice(0, -1) : host await expect( - client.index(indexPk.uid).getDocuments() + client.index(indexPk.uid).getDocuments() ).rejects.toHaveProperty( 'message', `request to ${strippedHost}/${route} failed, reason: connect ECONNREFUSED ${BAD_HOST.replace( diff --git a/tests/dump.test.ts b/tests/dump.test.ts index 9cc058924..534c8fc68 100644 --- a/tests/dump.test.ts +++ b/tests/dump.test.ts @@ -2,7 +2,6 @@ import { ErrorStatusCode } from '../src/types' import { clearAllIndexes, config, - waitForDumpProcessing, MeiliSearch, BAD_HOST, getClient, @@ -17,21 +16,9 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( ({ permission }) => { test(`${permission} key: create a new dump`, async () => { const client = await getClient(permission) - const response = await client.createDump() - expect(response.uid).toBeDefined() - expect(response.status).toEqual('in_progress') - await waitForDumpProcessing(response.uid, client) - }) + const { taskUid } = await client.createDump() - test(`${permission} key: get dump status`, async () => { - const client = await getClient(permission) - const enqueuedDump = await client.createDump() - await waitForDumpProcessing(enqueuedDump.uid, client) - const response = await client.getDumpStatus(enqueuedDump.uid) - expect(response.uid).toEqual(enqueuedDump.uid) - expect(response.status).toBeDefined() - expect(response.startedAt).toBeDefined() - expect(response.finishedAt).toBeDefined() + await client.waitForTask(taskUid) }) } ) @@ -46,14 +33,6 @@ describe.each([{ permission: 'Public' }])( ErrorStatusCode.INVALID_API_KEY ) }) - - test(`${permission} key: try to get dump status with search key and be denied`, async () => { - const client = await getClient(permission) - await expect(client.getDumpStatus('dumpUid')).rejects.toHaveProperty( - 'code', - ErrorStatusCode.INVALID_API_KEY - ) - }) } ) @@ -67,14 +46,6 @@ describe.each([{ permission: 'No' }])( ErrorStatusCode.MISSING_AUTHORIZATION_HEADER ) }) - - test(`${permission} key: try to get dump status with no key and be denied`, async () => { - const client = await getClient(permission) - await expect(client.getDumpStatus('dumpUid')).rejects.toHaveProperty( - 'code', - ErrorStatusCode.MISSING_AUTHORIZATION_HEADER - ) - }) } ) @@ -96,17 +67,4 @@ describe.each([ )}` ) }) - - test(`Test getDumpStatus route`, async () => { - const route = `dumps/1/status` - const client = new MeiliSearch({ host }) - const strippedHost = trailing ? host.slice(0, -1) : host - await expect(client.getDumpStatus('1')).rejects.toHaveProperty( - 'message', - `request to ${strippedHost}/${route} failed, reason: connect ECONNREFUSED ${BAD_HOST.replace( - 'http://', - '' - )}` - ) - }) }) diff --git a/tests/env/browser/index.html b/tests/env/browser/index.html index b4598b87c..092a96469 100644 --- a/tests/env/browser/index.html +++ b/tests/env/browser/index.html @@ -26,10 +26,10 @@ apiKey: 'masterKey', }) const task = await client.createIndex(UID) - await client.waitForTask(task.uid) + await client.waitForTask(task.taskUid) const documentTask = await client.index(UID).addDocuments([{ id: 1, title: "wonder woman" }]) - await client.waitForTask(documentTask.uid) + await client.waitForTask(documentTask.taskUid) const index = await client.index(UID).getRawInfo() diff --git a/tests/env/esm/src/index.js b/tests/env/esm/src/index.js index 6a79377f9..96f6b2fb7 100644 --- a/tests/env/esm/src/index.js +++ b/tests/env/esm/src/index.js @@ -3,5 +3,5 @@ import * as DefaultMeiliSearch from '../../../../' const client = new MeiliSearch({ host:'http://localhost:7700', apiKey: 'masterKey'}) const defaultClient = new DefaultMeiliSearch.MeiliSearch({ host:'http://localhost:7700', apiKey: 'masterKey'}) -const token = client.generateTenantToken([]) +const token = client.generateTenantToken('e489fe16-3381-431b-bee3-00430192915d', []) console.log({ client, token, defaultClient }) diff --git a/tests/env/express/public/headers.html b/tests/env/express/public/headers.html index 7be21ba33..798ffbad8 100644 --- a/tests/env/express/public/headers.html +++ b/tests/env/express/public/headers.html @@ -24,7 +24,7 @@ let error = 'NO ERRORS' try { const task = await client.createIndex(UID) - await client.waitForTask(task.uid) + await client.waitForTask(task.taskUid) await fetch(`http://localhost:7700/indexes/${UID}/documents`, { method: 'POST', headers: { @@ -42,7 +42,7 @@ document.body.insertBefore(errorDiv, document.querySelector("#content")); const deleteTask = await client.index(UID).delete() - await client.waitForTask(deleteTask.uid) + await client.waitForTask(deleteTask.taskUid) })() diff --git a/tests/env/express/public/index.html b/tests/env/express/public/index.html index ffd25f5b3..b4666ff1e 100644 --- a/tests/env/express/public/index.html +++ b/tests/env/express/public/index.html @@ -28,10 +28,10 @@ try { const task = await client.createIndex(UID) - await client.waitForTask(task.uid) + await client.waitForTask(task.taskUid) const documentTask = await client.index(UID).addDocuments([{ id: 1, title: "wonder woman" }]) - await client.waitForTask(documentTask.uid) + await client.waitForTask(documentTask.taskUid) const index = await client.index(UID).getRawInfo() @@ -52,7 +52,7 @@ searchDiv.innerHTML = content document.body.insertBefore(searchDiv, document.querySelector("#content")); const deleteTask = await client.index(UID).delete() - await client.waitForTask(deleteTask.uid) + await client.waitForTask(deleteTask.taskUid) })() diff --git a/tests/env/node/getting_started.js b/tests/env/node/getting_started.js index 900cde673..0962ee706 100644 --- a/tests/env/node/getting_started.js +++ b/tests/env/node/getting_started.js @@ -28,6 +28,8 @@ const { MeiliSearch } = require('../../../dist/bundles/meilisearch.umd.js') console.log(response) // => { "updateId": 0 } + await client.waitForTask(response.taskUid) + const search = await index.search('philoudelphia') console.log({ search, hit: search.hits }) const filteredSearch = await index.search('Wonder', { @@ -39,7 +41,7 @@ const { MeiliSearch } = require('../../../dist/bundles/meilisearch.umd.js') '', { filter: ['genres = action'], - facetsDistribution: ['genres'] + facets: ['genres'] } ) console.log(JSON.stringify(facetedSearch)) diff --git a/tests/env/node/index.js b/tests/env/node/index.js index 6f5d8acec..a945aa95d 100644 --- a/tests/env/node/index.js +++ b/tests/env/node/index.js @@ -4,7 +4,7 @@ const DefaultMeiliSearch = require('../../../') const CJStest = new MeiliSearch({ host:'http://localhost:7700', apiKey: 'masterKey'}) const DefaultCJSTest = new DefaultMeiliSearch.MeiliSearch({ host:'http://localhost:7700', apiKey: 'masterKey'}) -DefaultCJSTest.generateTenantToken([]) // Resolved using the `main` field -CJStest.generateTenantToken([]) // Resolved using the `main` field +DefaultCJSTest.generateTenantToken('e489fe16-3381-431b-bee3-00430192915d', []) // Resolved using the `main` field +CJStest.generateTenantToken('e489fe16-3381-431b-bee3-00430192915d', []) // Resolved using the `main` field console.log({ CJStest, DefaultCJSTest }) diff --git a/tests/env/node/search_example.js b/tests/env/node/search_example.js index ebcaf930f..51fbf8d83 100644 --- a/tests/env/node/search_example.js +++ b/tests/env/node/search_example.js @@ -11,15 +11,15 @@ const indexUid = 'movies' const addDataset = async () => { await client.deleteIndex(indexUid) - const { uid } = await client.createIndex(indexUid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(indexUid) + await client.waitForTask(taskUid) const index = client.index(indexUid) const documents = await index.getDocuments() - if (documents.length === 0) { - const { uid } = await index.addDocuments(dataset) - await index.waitForTask(uid) + if (documents.results.length === 0) { + const { taskUid } = await index.addDocuments(dataset) + await index.waitForTask(taskUid) } } @@ -29,7 +29,7 @@ const addDataset = async () => { const resp = await index.search('Avengers', { limit: 1, attributesToHighlight: ['title'], - }, 'GET') + }) console.log({ resp }) console.log({ hit: resp.hits[0] }) })() diff --git a/tests/env/typescript-browser/src/index.ts b/tests/env/typescript-browser/src/index.ts index 69344df1b..5c1472bf7 100644 --- a/tests/env/typescript-browser/src/index.ts +++ b/tests/env/typescript-browser/src/index.ts @@ -1,4 +1,5 @@ -import { IndexResponse, MeiliSearch } from '../../../../' +import { MeiliSearch } from '../../../../' +import { IndexObject } from '../../../../src' const config = { host: 'http://127.0.0.1:7700', @@ -15,10 +16,10 @@ function greeter(person: string) { ;(async () => { const indexes = await client.getRawIndexes() console.log({ indexes }, 'hello') - const uids = indexes.map((index: IndexResponse) => index.uid) + const uids = indexes.results.map((index: IndexObject) => index.uid) document.body.innerHTML = `${greeter( user )} this is the list of all your indexes: \n ${uids.join(', ')}` - console.log(await client.generateTenantToken([])) // Resolved using the `browser` field + console.log(await client.generateTenantToken('e489fe16-3381-431b-bee3-00430192915d', [])) // Resolved using the `browser` field })() diff --git a/tests/env/typescript-node/src/index.ts b/tests/env/typescript-node/src/index.ts index 070130fc3..206cfd703 100644 --- a/tests/env/typescript-node/src/index.ts +++ b/tests/env/typescript-node/src/index.ts @@ -3,7 +3,7 @@ import { // @ts-ignore MeiliSearch, - IndexResponse, + IndexObject, SearchResponse, Hits, Hit, @@ -26,12 +26,12 @@ const indexUid = "movies" ;(async () => { await client.deleteIndex(indexUid) - const { uid } = await client.createIndex(indexUid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(indexUid) + await client.waitForTask(taskUid) const index = client.index(indexUid) const indexes = await client.getRawIndexes() - indexes.map((index: IndexResponse) => { + indexes.results.map((index: IndexObject) => { console.log(index.uid) // console.log(index.something) -> ERROR }) @@ -42,7 +42,7 @@ const indexUid = "movies" attributesToHighlight: ['title'], // test: true -> ERROR Test does not exist on type SearchParams } - indexes.map((index: IndexResponse) => index.uid) + indexes.results.map((index: IndexObject) => index.uid) const res: SearchResponse = await index.search( 'avenger', searchParams @@ -59,7 +59,7 @@ const indexUid = "movies" console.log(hit?._formatted?.title) }) - console.log(await client.generateTenantToken([])) + console.log(await client.generateTenantToken('e489fe16-3381-431b-bee3-00430192915d', [])) await index.delete() })() diff --git a/tests/filterable_attributes.test.ts b/tests/filterable_attributes.test.ts index 78c99ebca..64f985a06 100644 --- a/tests/filterable_attributes.test.ts +++ b/tests/filterable_attributes.test.ts @@ -1,4 +1,4 @@ -import { ErrorStatusCode, EnqueuedTask } from '../src/types' +import { ErrorStatusCode } from '../src/types' import { clearAllIndexes, config, @@ -23,8 +23,8 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( ({ permission }) => { beforeEach(async () => { const client = await getClient('Master') - const { uid } = await client.index(index.uid).addDocuments(dataset) - await client.waitForTask(uid) + const { taskUid } = await client.index(index.uid).addDocuments(dataset) + await client.waitForTask(taskUid) }) test(`${permission} key: Get default attributes for filtering`, async () => { @@ -32,17 +32,17 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( const response: string[] = await client .index(index.uid) .getFilterableAttributes() + expect(response.sort()).toEqual([]) }) test(`${permission} key: Update attributes for filtering`, async () => { const client = await getClient(permission) const newFilterableAttributes = ['genre'] - const task: EnqueuedTask = await client + const task = await client .index(index.uid) .updateFilterableAttributes(newFilterableAttributes) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + await client.index(index.uid).waitForTask(task.taskUid) const response: string[] = await client .index(index.uid) @@ -52,29 +52,27 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: Update attributes for filtering at null`, async () => { const client = await getClient(permission) - const task: EnqueuedTask = await client + const task = await client .index(index.uid) .updateFilterableAttributes(null) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + await client.index(index.uid).waitForTask(task.taskUid) const response: string[] = await client .index(index.uid) .getFilterableAttributes() + expect(response.sort()).toEqual([]) }) test(`${permission} key: Reset attributes for filtering`, async () => { const client = await getClient(permission) - const task: EnqueuedTask = await client - .index(index.uid) - .resetFilterableAttributes() - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + const task = await client.index(index.uid).resetFilterableAttributes() + await client.index(index.uid).waitForTask(task.taskUid) const response: string[] = await client .index(index.uid) .getFilterableAttributes() + expect(response.sort()).toEqual([]) }) } @@ -85,8 +83,8 @@ describe.each([{ permission: 'Public' }])( ({ permission }) => { beforeEach(async () => { const client = await getClient('Master') - const { uid } = await client.createIndex(index.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(index.uid) + await client.waitForTask(taskUid) }) test(`${permission} key: try to get attributes for filtering and be denied`, async () => { @@ -117,8 +115,8 @@ describe.each([{ permission: 'No' }])( ({ permission }) => { beforeEach(async () => { const client = await getClient('Master') - const { uid } = await client.createIndex(index.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(index.uid) + await client.waitForTask(taskUid) }) test(`${permission} key: try to get attributes for filtering and be denied`, async () => { diff --git a/tests/get_search.test.ts b/tests/get_search.test.ts index 1f5e92314..b90fa8fbf 100644 --- a/tests/get_search.test.ts +++ b/tests/get_search.test.ts @@ -68,13 +68,13 @@ describe.each([ beforeAll(async () => { await clearAllIndexes(config) const client = await getClient('Master') - const { uid: task1 } = await client.createIndex(index.uid) + const { taskUid: task1 } = await client.createIndex(index.uid) await client.waitForTask(task1) - const { uid: task2 } = await client.createIndex(emptyIndex.uid) + const { taskUid: task2 } = await client.createIndex(emptyIndex.uid) await client.waitForTask(task2) const newFilterableAttributes = ['genre', 'title', 'id'] - const { uid: task3 }: EnqueuedTask = await client + const { taskUid: task3 }: EnqueuedTask = await client .index(index.uid) .updateSettings({ filterableAttributes: newFilterableAttributes, @@ -82,7 +82,9 @@ describe.each([ }) await client.waitForTask(task3) - const { uid: task4 } = await client.index(index.uid).addDocuments(dataset) + const { taskUid: task4 } = await client + .index(index.uid) + .addDocuments(dataset) await client.waitForTask(task4) }) @@ -186,7 +188,7 @@ describe.each([ filter: 'title = "Le Petit Prince"', attributesToCrop: ['*'], cropLength: 5, - matches: true, + showMatchesPosition: true, }) expect(response).toHaveProperty('hits', expect.any(Array)) expect(response).toHaveProperty('offset', 0) @@ -194,7 +196,7 @@ describe.each([ expect(response).toHaveProperty('processingTimeMs', expect.any(Number)) expect(response).toHaveProperty('query', 'prince') expect(response.hits.length).toEqual(1) - expect(response.hits[0]).toHaveProperty('_matchesInfo', { + expect(response.hits[0]).toHaveProperty('_matchesPosition', { comment: [{ start: 22, length: 6 }], title: [{ start: 9, length: 6 }], }) @@ -210,8 +212,9 @@ describe.each([ cropLength: 6, attributesToHighlight: ['*'], filter: 'title = "Le Petit Prince"', - matches: true, + showMatchesPosition: true, }) + expect(response).toHaveProperty('hits', expect.any(Array)) expect(response).toHaveProperty('offset', 0) expect(response).toHaveProperty('limit', 5) @@ -227,7 +230,10 @@ describe.each([ 'title', 'Le Petit Prince' ) - expect(response.hits[0]).toHaveProperty('_matchesInfo', expect.any(Object)) + expect(response.hits[0]).toHaveProperty( + '_matchesPosition', + expect.any(Object) + ) }) test(`${permission} key: search on default cropping parameters`, async () => { @@ -281,7 +287,7 @@ describe.each([ cropLength: 6, attributesToHighlight: ['*'], filter: 'title = "Le Petit Prince"', - matches: true, + showMatchesPosition: true, }) expect(response).toHaveProperty('hits', expect.any(Array)) expect(response).toHaveProperty('offset', 0) @@ -294,7 +300,10 @@ describe.each([ 'title', 'Le Petit Prince' ) - expect(response.hits[0]).toHaveProperty('_matchesInfo', expect.any(Object)) + expect(response.hits[0]).toHaveProperty( + '_matchesPosition', + expect.any(Object) + ) }) test(`${permission} key: search with all options but specific fields`, async () => { @@ -307,7 +316,7 @@ describe.each([ cropLength: 6, attributesToHighlight: ['id', 'title'], filter: 'title = "Le Petit Prince"', - matches: true, + showMatchesPosition: true, }) expect(response).toHaveProperty('hits', expect.any(Array)) expect(response).toHaveProperty('offset', 0) @@ -328,20 +337,21 @@ describe.each([ 'Le Petit Prince' ) expect(response.hits[0]._formatted).not.toHaveProperty('comment') - expect(response.hits[0]).toHaveProperty('_matchesInfo', expect.any(Object)) + expect(response.hits[0]).toHaveProperty( + '_matchesPosition', + expect.any(Object) + ) }) - test(`${permission} key: search with filter and facetsDistribution`, async () => { + test(`${permission} key: search with filter and facetDistribution`, async () => { const client = await getClient(permission) const response = await client.index(index.uid).searchGet('a', { filter: 'genre = romance', - facetsDistribution: ['genre'], + facets: ['genre'], }) - expect(response).toHaveProperty('facetsDistribution', { + expect(response).toHaveProperty('facetDistribution', { genre: { romance: 2 }, }) - expect(response).toHaveProperty('exhaustiveFacetsCount', false) - expect(response).toHaveProperty('exhaustiveNbHits', false) expect(response).toHaveProperty('hits', expect.any(Array)) expect(response.hits.length).toEqual(2) }) @@ -350,9 +360,8 @@ describe.each([ const client = await getClient(permission) const response = await client.index(index.uid).searchGet('a', { filter: 'id < 0', - facetsDistribution: ['genre'], + facets: ['genre'], }) - expect(response).toHaveProperty('exhaustiveNbHits', false) expect(response).toHaveProperty('hits', expect.any(Array)) expect(response.hits.length).toEqual(0) }) @@ -370,13 +379,11 @@ describe.each([ const client = await getClient(permission) const response = await client.index(index.uid).searchGet('a', { filter: 'genre = romance AND (genre = romance OR genre = romance)', - facetsDistribution: ['genre'], + facets: ['genre'], }) - expect(response).toHaveProperty('facetsDistribution', { + expect(response).toHaveProperty('facetDistribution', { genre: { romance: 2 }, }) - expect(response).toHaveProperty('exhaustiveFacetsCount', false) - expect(response).toHaveProperty('exhaustiveNbHits', false) expect(response).toHaveProperty('hits', expect.any(Array)) expect(response.hits.length).toEqual(2) }) @@ -385,9 +392,9 @@ describe.each([ const client = await getClient(permission) const response = await client.index(index.uid).searchGet(undefined, { filter: 'genre = fantasy', - facetsDistribution: ['genre'], + facets: ['genre'], }) - expect(response).toHaveProperty('facetsDistribution', { + expect(response).toHaveProperty('facetDistribution', { genre: { fantasy: 2 }, }) expect(response.hits.length).toEqual(2) @@ -397,22 +404,23 @@ describe.each([ const client = await getClient(permission) const response = await client.index(index.uid).searchGet(null, { filter: 'genre = fantasy', - facetsDistribution: ['genre'], + facets: ['genre'], }) - expect(response).toHaveProperty('facetsDistribution', { + expect(response).toHaveProperty('facetDistribution', { genre: { fantasy: 2 }, }) expect(response.hits.length).toEqual(2) - expect(response.nbHits).toEqual(2) + expect(response.estimatedTotalHits).toEqual(2) }) test(`${permission} key: search with multiple filter and empty string query (placeholder)`, async () => { const client = await getClient(permission) const response = await client.index(index.uid).searchGet('', { filter: 'genre = fantasy', - facetsDistribution: ['genre'], + facets: ['genre'], }) - expect(response).toHaveProperty('facetsDistribution', { + + expect(response).toHaveProperty('facetDistribution', { genre: { fantasy: 2 }, }) expect(response.hits.length).toEqual(2) @@ -433,8 +441,8 @@ describe.each([ test(`${permission} key: Try to search on deleted index and fail`, async () => { const client = await getClient(permission) const masterClient = await getClient('Master') - const { uid } = await masterClient.index(index.uid).delete() - await masterClient.waitForTask(uid) + const { taskUid } = await masterClient.index(index.uid).delete() + await masterClient.waitForTask(taskUid) await expect( client.index(index.uid).searchGet('prince') ).rejects.toHaveProperty('code', ErrorStatusCode.INDEX_NOT_FOUND) diff --git a/tests/index.test.ts b/tests/index.test.ts index dcded393e..e90a31594 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -1,4 +1,4 @@ -import { IndexResponse, ErrorStatusCode } from '../src/types' +import { ErrorStatusCode } from '../src/types' import { clearAllIndexes, config, @@ -28,16 +28,15 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: create index with NO primary key`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexNoPk.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(indexNoPk.uid) + await client.waitForTask(taskUid) + const newIndex = await client.getIndex(indexNoPk.uid) expect(newIndex).toHaveProperty('uid', indexNoPk.uid) expect(newIndex).toHaveProperty('primaryKey', null) - const rawIndex: IndexResponse = await client - .index(indexNoPk.uid) - .getRawInfo() + const rawIndex = await client.index(indexNoPk.uid).getRawInfo() expect(rawIndex).toHaveProperty('uid', indexNoPk.uid) expect(rawIndex).toHaveProperty('primaryKey', null) @@ -47,18 +46,18 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: create index with primary key`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexPk.uid, { + const { taskUid } = await client.createIndex(indexPk.uid, { primaryKey: indexPk.primaryKey, }) - await client.waitForTask(uid) + await client.waitForTask(taskUid) + const newIndex = await client.getIndex(indexPk.uid) expect(newIndex).toHaveProperty('uid', indexPk.uid) expect(newIndex).toHaveProperty('primaryKey', indexPk.primaryKey) - const rawIndex: IndexResponse = await client - .index(indexPk.uid) - .getRawInfo() + const rawIndex = await client.index(indexPk.uid).getRawInfo() + expect(rawIndex).toHaveProperty('uid', indexPk.uid) expect(rawIndex).toHaveProperty('primaryKey', indexPk.primaryKey) expect(rawIndex).toHaveProperty('createdAt', expect.any(String)) @@ -67,22 +66,23 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: Get raw index that exists`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexPk.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(indexPk.uid) + await client.waitForTask(taskUid) const response = await client.getRawIndex(indexPk.uid) + expect(response).toHaveProperty('uid', indexPk.uid) }) test(`${permission} key: Get all indexes in Index instances`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexPk.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(indexPk.uid) + await client.waitForTask(taskUid) - const response = await client.getRawIndexes() + const { results } = await client.getRawIndexes() - expect(response.length).toEqual(1) - expect(response[0].uid).toEqual(indexPk.uid) + expect(results.length).toEqual(1) + expect(results[0].uid).toEqual(indexPk.uid) }) test(`${permission} key: Get index that does not exist`, async () => { @@ -103,10 +103,11 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: Get raw index info through client with primary key`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexPk.uid, { + const { taskUid } = await client.createIndex(indexPk.uid, { primaryKey: indexPk.primaryKey, }) - await client.waitForTask(uid) + await client.waitForTask(taskUid) + const response = await client.getRawIndex(indexPk.uid) expect(response).toHaveProperty('uid', indexPk.uid) @@ -115,8 +116,8 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: Get raw index info through client with NO primary key`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexNoPk.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(indexNoPk.uid) + await client.waitForTask(taskUid) const response = await client.getRawIndex(indexNoPk.uid) @@ -126,10 +127,11 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: Get raw index info with primary key`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexPk.uid, { + const { taskUid } = await client.createIndex(indexPk.uid, { primaryKey: indexPk.primaryKey, }) - await client.waitForTask(uid) + await client.waitForTask(taskUid) + const response = await client.index(indexPk.uid).getRawInfo() expect(response).toHaveProperty('uid', indexPk.uid) @@ -138,113 +140,143 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: Get raw index info with NO primary key`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexNoPk.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(indexNoPk.uid) + await client.waitForTask(taskUid) const response = await client.index(indexNoPk.uid).getRawInfo() + expect(response).toHaveProperty('uid', indexNoPk.uid) expect(response).toHaveProperty('primaryKey', null) }) test(`${permission} key: fetch index with primary key`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexPk.uid, { + const { taskUid } = await client.createIndex(indexPk.uid, { primaryKey: indexPk.primaryKey, }) - await client.waitForTask(uid) + await client.waitForTask(taskUid) const index = client.index(indexPk.uid) const response = await index.fetchInfo() + expect(response).toHaveProperty('uid', indexPk.uid) expect(response).toHaveProperty('primaryKey', indexPk.primaryKey) }) test(`${permission} key: fetch primary key on an index with primary key`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexPk.uid, { + const { taskUid } = await client.createIndex(indexPk.uid, { primaryKey: indexPk.primaryKey, }) - await client.waitForTask(uid) + await client.waitForTask(taskUid) const index = client.index(indexPk.uid) const response: string | undefined = await index.fetchPrimaryKey() + expect(response).toBe(indexPk.primaryKey) }) test(`${permission} key: fetch primary key on an index with NO primary key`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexNoPk.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(indexNoPk.uid) + await client.waitForTask(taskUid) const index = client.index(indexNoPk.uid) const response: string | undefined = await index.fetchPrimaryKey() + expect(response).toBe(null) }) test(`${permission} key: fetch index with primary key`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexPk.uid, { + const { taskUid } = await client.createIndex(indexPk.uid, { primaryKey: indexPk.primaryKey, }) - await client.waitForTask(uid) + await client.waitForTask(taskUid) const index = client.index(indexPk.uid) const response = await index.fetchInfo() + expect(response).toHaveProperty('uid', indexPk.uid) expect(response).toHaveProperty('primaryKey', indexPk.primaryKey) }) test(`${permission} key: fetch index with NO primary key`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexNoPk.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(indexNoPk.uid) + await client.waitForTask(taskUid) const index = client.index(indexNoPk.uid) const response = await index.fetchInfo() + expect(response).toHaveProperty('uid', indexNoPk.uid) expect(response).toHaveProperty('primaryKey', null) }) - test(`${permission} key: update primary key on an index that has no primary key already`, async () => { + test(`${permission} key: get all indexes`, async () => { const client = await getClient(permission) - const { uid: createTask } = await client.createIndex(indexNoPk.uid) - await client.waitForTask(createTask) + const task1 = await client.createIndex(indexNoPk.uid) + const task2 = await client.createIndex(indexPk.uid) + await client.waitForTask(task1.taskUid) + await client.waitForTask(task2.taskUid) + + const indexes = await client.getIndexes() + + expect(indexes.results.length).toEqual(2) + }) + + test(`${permission} key: get all indexes with filters`, async () => { + const client = await getClient(permission) + const task1 = await client.createIndex(indexNoPk.uid) + const task2 = await client.createIndex(indexPk.uid) + await client.waitForTask(task1.taskUid) + await client.waitForTask(task2.taskUid) - const { uid: updateTask } = await client.index(indexNoPk.uid).update({ + const indexes = await client.getIndexes({ limit: 1, offset: 1 }) + + expect(indexes.results.length).toEqual(1) + expect(indexes.results[0].uid).toEqual(indexPk.uid) + }) + + test(`${permission} key: update primary key on an index that has no primary key already`, async () => { + const client = await getClient(permission) + const { taskUid: createTask } = await client.createIndex(indexNoPk.uid) + const { taskUid: updateTask } = await client.index(indexNoPk.uid).update({ primaryKey: 'newPrimaryKey', }) + await client.waitForTask(createTask) await client.waitForTask(updateTask) const index = await client.getIndex(indexNoPk.uid) + expect(index).toHaveProperty('uid', indexNoPk.uid) expect(index).toHaveProperty('primaryKey', 'newPrimaryKey') }) test(`${permission} key: update primary key on an index that has NO primary key already through client`, async () => { const client = await getClient(permission) - const { uid: createTask } = await client.createIndex(indexNoPk.uid) - await client.waitForTask(createTask) - - const { uid: updateTask } = await client.updateIndex(indexNoPk.uid, { + const { taskUid: createTask } = await client.createIndex(indexNoPk.uid) + const { taskUid: updateTask } = await client.updateIndex(indexNoPk.uid, { primaryKey: indexPk.primaryKey, }) + await client.waitForTask(createTask) await client.waitForTask(updateTask) const index = await client.getIndex(indexNoPk.uid) + expect(index).toHaveProperty('uid', indexNoPk.uid) expect(index).toHaveProperty('primaryKey', indexPk.primaryKey) }) test(`${permission} key: update primary key on an index that has already a primary key and fail through client`, async () => { const client = await getClient(permission) - const { uid: createTask } = await client.createIndex(indexPk.uid, { + const { taskUid: createTask } = await client.createIndex(indexPk.uid, { primaryKey: indexPk.primaryKey, }) - await client.waitForTask(createTask) - - const { uid: updateTask } = await client.updateIndex(indexPk.uid, { + const { taskUid: updateTask } = await client.updateIndex(indexPk.uid, { primaryKey: 'newPrimaryKey', }) + await client.waitForTask(createTask) await client.waitForTask(updateTask) const index = await client.getIndex(indexPk.uid) @@ -255,14 +287,13 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: update primary key on an index that has already a primary key and fail`, async () => { const client = await getClient(permission) - const { uid: createTask } = await client.createIndex(indexPk.uid, { + const { taskUid: createTask } = await client.createIndex(indexPk.uid, { primaryKey: indexPk.primaryKey, }) - await client.waitForTask(createTask) - - const { uid: updateTask } = await client.index(indexPk.uid).update({ + const { taskUid: updateTask } = await client.index(indexPk.uid).update({ primaryKey: 'newPrimaryKey', }) + await client.waitForTask(createTask) await client.waitForTask(updateTask) const index = await client.getIndex(indexPk.uid) @@ -273,22 +304,25 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: delete index`, async () => { const client = await getClient(permission) - const { uid: createTask } = await client.createIndex(indexNoPk.uid) + const { taskUid: createTask } = await client.createIndex(indexNoPk.uid) + const { taskUid: deleteTask } = await client.index(indexNoPk.uid).delete() await client.waitForTask(createTask) + await client.waitForTask(deleteTask) - const { uid: updateTask } = await client.index(indexNoPk.uid).delete() - await client.waitForTask(updateTask) + const { results } = await client.getIndexes() - await expect(client.getIndexes()).resolves.toHaveLength(0) + expect(results).toHaveLength(0) }) test(`${permission} key: delete index using client`, async () => { const client = await getClient(permission) await client.createIndex(indexPk.uid) - const { uid } = await client.deleteIndex(indexPk.uid) - await client.waitForTask(uid) + const { taskUid } = await client.deleteIndex(indexPk.uid) + await client.waitForTask(taskUid) + + const { results } = await client.getIndexes() - await expect(client.getIndexes()).resolves.toHaveLength(0) + expect(results).toHaveLength(0) }) test(`${permission} key: fetch deleted index should fail`, async () => { @@ -311,17 +345,20 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: delete index with uid that does not exist should fail`, async () => { const client = await getClient(permission) const index = client.index(indexNoPk.uid) - const { uid } = await index.delete() - const task = await client.waitForTask(uid) + const { taskUid } = await index.delete() + + const task = await client.waitForTask(taskUid) + expect(task.status).toBe('failed') }) test(`${permission} key: get stats of an index`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexNoPk.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(indexNoPk.uid) + await client.waitForTask(taskUid) const response = await client.index(indexNoPk.uid).getStats() + expect(response).toHaveProperty('numberOfDocuments', 0) expect(response).toHaveProperty('isIndexing', false) expect(response).toHaveProperty('fieldDistribution', {}) @@ -329,8 +366,8 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: Get updatedAt and createdAt through fetch info`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexPk.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(indexPk.uid) + await client.waitForTask(taskUid) const index = await client.index(indexPk.uid).fetchInfo() @@ -340,8 +377,8 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: Get updatedAt and createdAt index through getRawInfo`, async () => { const client = await getClient(permission) - const { uid } = await client.createIndex(indexPk.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(indexPk.uid) + await client.waitForTask(taskUid) const index = client.index(indexPk.uid) diff --git a/tests/keys.test.ts b/tests/keys.test.ts index f7ab8edf8..54c5362dc 100644 --- a/tests/keys.test.ts +++ b/tests/keys.test.ts @@ -1,4 +1,4 @@ -import { ErrorStatusCode, Key } from '../src/types' +import { ErrorStatusCode } from '../src/types' import { clearAllIndexes, config, @@ -10,175 +10,167 @@ beforeEach(async () => { await clearAllIndexes(config) }) -describe.each([{ permission: 'Master' }])('Test on keys', ({ permission }) => { - beforeEach(async () => { - await clearAllIndexes(config) - }) - test(`${permission} key: get keys`, async () => { - const client = await getClient(permission) - const { results: keys } = await client.getKeys() - - const defaultKey = keys.find((key: Key) => - key.description.startsWith('Default Search API') - ) - - expect(defaultKey).toBeDefined() - expect(defaultKey).toHaveProperty( - 'description', - 'Default Search API Key (Use it to search from the frontend)' - ) - expect(defaultKey).toHaveProperty('key') - expect(defaultKey).toHaveProperty('actions') - expect(defaultKey).toHaveProperty('indexes') - expect(defaultKey).toHaveProperty('expiresAt', null) - expect(defaultKey).toHaveProperty('createdAt') - expect(defaultKey).toHaveProperty('updatedAt') - - const adminKey = keys.find((key: Key) => - key.description.startsWith('Default Admin API Key') - ) - - expect(adminKey).toBeDefined() - expect(adminKey).toHaveProperty( - 'description', - 'Default Admin API Key (Use it for all other operations. Caution! Do not use it on a public frontend)' - ) - expect(adminKey).toHaveProperty('key') - expect(adminKey).toHaveProperty('actions') - expect(adminKey).toHaveProperty('indexes') - expect(adminKey).toHaveProperty('expiresAt', null) - expect(adminKey).toHaveProperty('createdAt') - expect(adminKey).toHaveProperty('updatedAt') - }) - - test(`${permission} key: get on key`, async () => { - const client = await getClient(permission) - const apiKey = await getKey('Private') - - const key = await client.getKey(apiKey) - - expect(key).toBeDefined() - expect(key).toHaveProperty( - 'description', - 'Default Admin API Key (Use it for all other operations. Caution! Do not use it on a public frontend)' - ) - expect(key).toHaveProperty('key') - expect(key).toHaveProperty('actions') - expect(key).toHaveProperty('indexes') - expect(key).toHaveProperty('expiresAt', null) - expect(key).toHaveProperty('createdAt') - expect(key).toHaveProperty('updatedAt') - }) - - test(`${permission} key: create key with no expiresAt`, async () => { - const client = await getClient(permission) - - const key = await client.createKey({ - description: 'Indexing Products API key', - actions: ['documents.add'], - indexes: ['products'], - expiresAt: null, +afterAll(() => { + return clearAllIndexes(config) +}) + +describe.each([{ permission: 'Master' }, { permission: 'Private' }])( + 'Test on keys', + ({ permission }) => { + beforeEach(async () => { + const client = await getClient('Master') + await clearAllIndexes(config) + + const keys = await client.getKeys() + + const customKeys = keys.results.filter( + (key) => + key.name !== 'Default Search API Key' && + key.name !== 'Default Admin API Key' + ) + + // Delete all custom keys + await Promise.all(customKeys.map((key) => client.deleteKey(key.uid))) }) - expect(key).toBeDefined() - expect(key).toHaveProperty('description', 'Indexing Products API key') - expect(key).toHaveProperty('key') - expect(key).toHaveProperty('actions') - expect(key).toHaveProperty('indexes') - expect(key).toHaveProperty('expiresAt', null) - expect(key).toHaveProperty('createdAt') - expect(key).toHaveProperty('updatedAt') - }) - - test(`${permission} key: create key with an expiresAt`, async () => { - const client = await getClient(permission) - - const key = await client.createKey({ - description: 'Indexing Products API key', - actions: ['documents.add'], - indexes: ['products'], - expiresAt: '2050-11-13T00:00:00Z', // Test will fail in 2050 + test(`${permission} key: get keys`, async () => { + const client = await getClient(permission) + const keys = await client.getKeys() + + const searchKey = keys.results.find( + (key: any) => key.name === 'Default Search API Key' + ) + + expect(searchKey).toBeDefined() + expect(searchKey).toHaveProperty( + 'description', + 'Use it to search from the frontend' + ) + expect(searchKey).toHaveProperty('key') + expect(searchKey).toHaveProperty('actions') + expect(searchKey).toHaveProperty('indexes') + expect(searchKey).toHaveProperty('expiresAt', null) + expect(searchKey).toHaveProperty('createdAt') + expect(searchKey).toHaveProperty('updatedAt') + + const adminKey = keys.results.find( + (key: any) => key.name === 'Default Admin API Key' + ) + + expect(adminKey).toBeDefined() + expect(adminKey).toHaveProperty( + 'description', + 'Use it for anything that is not a search operation. Caution! Do not expose it on a public frontend' + ) + expect(adminKey).toHaveProperty('key') + expect(adminKey).toHaveProperty('actions') + expect(adminKey).toHaveProperty('indexes') + expect(adminKey).toHaveProperty('expiresAt', null) + expect(adminKey).toHaveProperty('createdAt') + expect(adminKey).toHaveProperty('updatedAt') }) - expect(key).toBeDefined() - expect(key).toHaveProperty('description', 'Indexing Products API key') - expect(key).toHaveProperty('key') - expect(key).toHaveProperty('actions', ['documents.add']) - expect(key).toHaveProperty('indexes') - expect(key).toHaveProperty('expiresAt', '2050-11-13T00:00:00Z') - expect(key).toHaveProperty('createdAt') - expect(key).toHaveProperty('updatedAt') - }) - - test(`${permission} key: update a key`, async () => { - const client = await getClient(permission) - - const key = await client.createKey({ - description: 'Indexing Products API key', - actions: ['documents.add'], - indexes: ['products'], - expiresAt: '2050-11-13T00:00:00Z', // Test will fail in 2050 + test(`${permission} key: get keys with pagination`, async () => { + const client = await getClient(permission) + const keys = await client.getKeys({ limit: 1, offset: 2 }) + + expect(keys.limit).toEqual(1) + expect(keys.offset).toEqual(2) + expect(keys.total).toEqual(2) }) - const updatedKey = await client.updateKey(key.key, { - description: 'Indexing Products API key', - actions: ['documents.add'], - indexes: ['products'], - expiresAt: '2050-11-13T00:00:00Z', // Test will fail in 2050 + test(`${permission} key: get on key`, async () => { + const client = await getClient(permission) + const apiKey = await getKey('Private') + + const key = await client.getKey(apiKey) + + expect(key).toBeDefined() + expect(key).toHaveProperty( + 'description', + 'Use it for anything that is not a search operation. Caution! Do not expose it on a public frontend' + ) + expect(key).toHaveProperty('key') + expect(key).toHaveProperty('actions') + expect(key).toHaveProperty('indexes') + expect(key).toHaveProperty('expiresAt', null) + expect(key).toHaveProperty('createdAt') + expect(key).toHaveProperty('updatedAt') }) - expect(updatedKey).toBeDefined() - expect(updatedKey).toHaveProperty( - 'description', - 'Indexing Products API key' - ) - expect(updatedKey).toHaveProperty('key') - expect(updatedKey).toHaveProperty('actions') - expect(updatedKey).toHaveProperty('indexes') - expect(updatedKey).toHaveProperty('expiresAt', '2050-11-13T00:00:00Z') - expect(updatedKey).toHaveProperty('createdAt') - expect(updatedKey).toHaveProperty('updatedAt') - }) - - test(`${permission} key: delete a key`, async () => { - const client = await getClient(permission) - - const key = await client.createKey({ - description: 'Indexing Products API key', - actions: ['documents.add'], - indexes: ['products'], - expiresAt: '2050-11-13T00:00:00Z', // Test will fail in 2050 + test(`${permission} key: create key with no expiresAt`, async () => { + const client = await getClient(permission) + const uid = '3db051e0-423d-4b5c-a63a-f82a7043dce6' + + const key = await client.createKey({ + uid, + description: 'Indexing Products API key', + actions: ['documents.add'], + indexes: ['products'], + expiresAt: null, + }) + + expect(key).toBeDefined() + expect(key).toHaveProperty('description', 'Indexing Products API key') + expect(key).toHaveProperty('uid', uid) + expect(key).toHaveProperty('expiresAt', null) }) - const deletedKey = await client.deleteKey(key.key) - expect(deletedKey).toBeUndefined() - }) -}) + test(`${permission} key: create key with an expiresAt`, async () => { + const client = await getClient(permission) -describe.each([{ permission: 'Private' }])( - 'Test on keys with admin key', - ({ permission }) => { - test(`${permission} key: get keys denied`, async () => { + const key = await client.createKey({ + description: 'Indexing Products API key', + actions: ['documents.add'], + indexes: ['products'], + expiresAt: '2050-11-13T00:00:00Z', // Test will fail in 2050 + }) + + expect(key).toBeDefined() + expect(key).toHaveProperty('description', 'Indexing Products API key') + expect(key).toHaveProperty('expiresAt', '2050-11-13T00:00:00Z') + }) + + test(`${permission} key: update a key`, async () => { const client = await getClient(permission) - await expect(client.getKeys()).rejects.toHaveProperty( - 'code', - ErrorStatusCode.INVALID_API_KEY + + const key = await client.createKey({ + description: 'Indexing Products API key', + actions: ['documents.add'], + indexes: ['products'], + expiresAt: '2050-11-13T00:00:00Z', // Test will fail in 2050 + }) + + const updatedKey = await client.updateKey(key.key, { + description: 'Indexing Products API key 2', + name: 'Product admin', + }) + + expect(updatedKey).toBeDefined() + expect(updatedKey).toHaveProperty( + 'description', + 'Indexing Products API key 2' ) + expect(updatedKey).toHaveProperty('name', 'Product admin') }) - test(`${permission} key: create key denied`, async () => { + test(`${permission} key: delete a key`, async () => { const client = await getClient(permission) - await expect( - client.createKey({ - description: 'Indexing Products API key', - actions: ['documents.add'], - indexes: ['products'], - expiresAt: null, - }) - ).rejects.toHaveProperty('code', ErrorStatusCode.INVALID_API_KEY) + + const key = await client.createKey({ + description: 'Indexing Products API key', + actions: ['documents.add'], + indexes: ['products'], + expiresAt: '2050-11-13T00:00:00Z', // Test will fail in 2050 + }) + + const deletedKey = await client.deleteKey(key.key) + + expect(deletedKey).toBeUndefined() }) } ) + describe.each([{ permission: 'Public' }])( 'Test on keys with search key', ({ permission }) => { diff --git a/tests/ranking_rules.test.ts b/tests/ranking_rules.test.ts index 411b45f9d..487d781e0 100644 --- a/tests/ranking_rules.test.ts +++ b/tests/ranking_rules.test.ts @@ -33,8 +33,8 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( beforeEach(async () => { await clearAllIndexes(config) const client = await getClient('master') - const { uid } = await client.index(index.uid).addDocuments(dataset) - await client.waitForTask(uid) + const { taskUid } = await client.index(index.uid).addDocuments(dataset) + await client.waitForTask(taskUid) }) test(`${permission} key: Get default ranking rules`, async () => { @@ -49,10 +49,10 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( const task: EnqueuedTask = await client .index(index.uid) .updateRankingRules(newRankingRules) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + await client.index(index.uid).waitForTask(task.taskUid) const response: string[] = await client.index(index.uid).getRankingRules() + expect(response).toEqual(newRankingRules) }) @@ -61,10 +61,10 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( const task: EnqueuedTask = await client .index(index.uid) .updateRankingRules(null) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + await client.index(index.uid).waitForTask(task.taskUid) const response: string[] = await client.index(index.uid).getRankingRules() + expect(response).toEqual(defaultRankingRules) }) @@ -73,10 +73,10 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( const task: EnqueuedTask = await client .index(index.uid) .resetRankingRules() - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + await client.index(index.uid).waitForTask(task.taskUid) const response: string[] = await client.index(index.uid).getRankingRules() + expect(response).toEqual(defaultRankingRules) }) } diff --git a/tests/search.test.ts b/tests/search.test.ts index fb0adc843..533c51f5c 100644 --- a/tests/search.test.ts +++ b/tests/search.test.ts @@ -70,7 +70,7 @@ describe.each([ await client.createIndex(emptyIndex.uid) const newFilterableAttributes = ['genre', 'title', 'id'] - const { uid: task1 }: EnqueuedTask = await client + const { taskUid: task1 }: EnqueuedTask = await client .index(index.uid) .updateSettings({ filterableAttributes: newFilterableAttributes, @@ -78,7 +78,9 @@ describe.each([ }) await client.waitForTask(task1) - const { uid: task2 } = await client.index(index.uid).addDocuments(dataset) + const { taskUid: task2 } = await client + .index(index.uid) + .addDocuments(dataset) await client.waitForTask(task2) }) @@ -221,7 +223,7 @@ describe.each([ filter: 'title = "Le Petit Prince"', attributesToCrop: ['*'], cropLength: 5, - matches: true, + showMatchesPosition: true, }) expect(response).toHaveProperty('hits', expect.any(Array)) expect(response).toHaveProperty('offset', 0) @@ -229,7 +231,7 @@ describe.each([ expect(response).toHaveProperty('processingTimeMs', expect.any(Number)) expect(response).toHaveProperty('query', 'prince') expect(response.hits.length).toEqual(1) - expect(response.hits[0]).toHaveProperty('_matchesInfo', { + expect(response.hits[0]).toHaveProperty('_matchesPosition', { comment: [{ start: 22, length: 6 }], title: [{ start: 9, length: 6 }], }) @@ -245,7 +247,7 @@ describe.each([ cropLength: 6, attributesToHighlight: ['*'], filter: 'title = "Le Petit Prince"', - matches: true, + showMatchesPosition: true, }) expect(response).toHaveProperty('hits', expect.any(Array)) expect(response).toHaveProperty('offset', 0) @@ -262,7 +264,10 @@ describe.each([ 'title', 'Le Petit Prince' ) - expect(response.hits[0]).toHaveProperty('_matchesInfo', expect.any(Object)) + expect(response.hits[0]).toHaveProperty( + '_matchesPosition', + expect.any(Object) + ) }) test(`${permission} key: search on default cropping parameters`, async () => { @@ -316,7 +321,7 @@ describe.each([ cropLength: 6, attributesToHighlight: ['*'], filter: 'title = "Le Petit Prince"', - matches: true, + showMatchesPosition: true, }) expect(response).toHaveProperty('hits', expect.any(Array)) expect(response).toHaveProperty('offset', 0) @@ -329,7 +334,10 @@ describe.each([ 'title', 'Le Petit Prince' ) - expect(response.hits[0]).toHaveProperty('_matchesInfo', expect.any(Object)) + expect(response.hits[0]).toHaveProperty( + '_matchesPosition', + expect.any(Object) + ) }) test(`${permission} key: search with all options but specific fields`, async () => { @@ -342,7 +350,7 @@ describe.each([ cropLength: 6, attributesToHighlight: ['id', 'title'], filter: 'title = "Le Petit Prince"', - matches: true, + showMatchesPosition: true, }) expect(response).toHaveProperty('hits', expect.any(Array)) expect(response).toHaveProperty('offset', 0) @@ -363,7 +371,10 @@ describe.each([ 'Le Petit Prince' ) expect(response.hits[0]._formatted).not.toHaveProperty('comment') - expect(response.hits[0]).toHaveProperty('_matchesInfo', expect.any(Object)) + expect(response.hits[0]).toHaveProperty( + '_matchesPosition', + expect.any(Object) + ) }) test(`${permission} key: Search with specific fields in attributesToHighlight and check for types of number fields`, async () => { @@ -386,17 +397,16 @@ describe.each([ expect(response.hits[0]._formatted?.isTrue).toEqual(true) }) - test(`${permission} key: search with filter and facetsDistribution`, async () => { + test(`${permission} key: search with filter and facetDistribution`, async () => { const client = await getClient(permission) const response = await client.index(index.uid).search('a', { filter: ['genre = romance'], - facetsDistribution: ['genre'], + facets: ['genre'], }) - expect(response).toHaveProperty('facetsDistribution', { + + expect(response).toHaveProperty('facetDistribution', { genre: { romance: 2 }, }) - expect(response).toHaveProperty('exhaustiveFacetsCount', false) - expect(response).toHaveProperty('exhaustiveNbHits', false) expect(response).toHaveProperty('hits', expect.any(Array)) expect(response.hits.length).toEqual(2) }) @@ -406,7 +416,6 @@ describe.each([ const response = await client.index(index.uid).search('a', { filter: 'id < 0', }) - expect(response).toHaveProperty('exhaustiveNbHits', false) expect(response).toHaveProperty('hits', expect.any(Array)) expect(response.hits.length).toEqual(0) }) @@ -424,13 +433,11 @@ describe.each([ const client = await getClient(permission) const response = await client.index(index.uid).search('a', { filter: ['genre = romance', ['genre = romance', 'genre = romance']], - facetsDistribution: ['genre'], + facets: ['genre'], }) - expect(response).toHaveProperty('facetsDistribution', { + expect(response).toHaveProperty('facetDistribution', { genre: { romance: 2 }, }) - expect(response).toHaveProperty('exhaustiveFacetsCount', false) - expect(response).toHaveProperty('exhaustiveNbHits', false) expect(response).toHaveProperty('hits', expect.any(Array)) expect(response.hits.length).toEqual(2) }) @@ -439,9 +446,9 @@ describe.each([ const client = await getClient(permission) const response = await client.index(index.uid).search(undefined, { filter: ['genre = fantasy'], - facetsDistribution: ['genre'], + facets: ['genre'], }) - expect(response).toHaveProperty('facetsDistribution', { + expect(response).toHaveProperty('facetDistribution', { genre: { fantasy: 2 }, }) expect(response.hits.length).toEqual(2) @@ -451,22 +458,22 @@ describe.each([ const client = await getClient(permission) const response = await client.index(index.uid).search(null, { filter: ['genre = fantasy'], - facetsDistribution: ['genre'], + facets: ['genre'], }) - expect(response).toHaveProperty('facetsDistribution', { + expect(response).toHaveProperty('facetDistribution', { genre: { fantasy: 2 }, }) expect(response.hits.length).toEqual(2) - expect(response.nbHits).toEqual(2) + expect(response.estimatedTotalHits).toEqual(2) }) test(`${permission} key: search with multiple filter and empty string query (placeholder)`, async () => { const client = await getClient(permission) const response = await client.index(index.uid).search('', { filter: ['genre = fantasy'], - facetsDistribution: ['genre'], + facets: ['genre'], }) - expect(response).toHaveProperty('facetsDistribution', { + expect(response).toHaveProperty('facetDistribution', { genre: { fantasy: 2 }, }) expect(response.hits.length).toEqual(2) @@ -497,8 +504,8 @@ describe.each([ test(`${permission} key: Try to search on deleted index and fail`, async () => { const client = await getClient(permission) const masterClient = await getClient('Master') - const { uid } = await masterClient.index(index.uid).delete() - await masterClient.waitForTask(uid) + const { taskUid } = await masterClient.index(index.uid).delete() + await masterClient.waitForTask(taskUid) await expect( client.index(index.uid).search('prince', {}) @@ -511,8 +518,8 @@ describe.each([{ permission: 'No' }])( ({ permission }) => { beforeAll(async () => { const client = await getClient('Master') - const { uid } = await client.createIndex(index.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(index.uid) + await client.waitForTask(taskUid) }) test(`${permission} key: Try Basic search and be denied`, async () => { @@ -535,7 +542,7 @@ describe.each([{ permission: 'Master' }])( const client = await getClient('Master') await client.createIndex(index.uid) - const { uid: documentAdditionTask } = await client + const { taskUid: documentAdditionTask } = await client .index(index.uid) .addDocuments(datasetWithNests) await client.waitForTask(documentAdditionTask) @@ -557,7 +564,7 @@ describe.each([{ permission: 'Master' }])( test(`${permission} key: search on nested content with searchable on specific nested field`, async () => { const client = await getClient(permission) - const { uid: settingsUpdateTask }: EnqueuedTask = await client + const { taskUid: settingsUpdateTask }: EnqueuedTask = await client .index(index.uid) .updateSettings({ searchableAttributes: ['title', 'info.comment'], @@ -578,7 +585,7 @@ describe.each([{ permission: 'Master' }])( test(`${permission} key: search on nested content with sort`, async () => { const client = await getClient(permission) - const { uid: settingsUpdateTask }: EnqueuedTask = await client + const { taskUid: settingsUpdateTask }: EnqueuedTask = await client .index(index.uid) .updateSettings({ searchableAttributes: ['title', 'info.comment'], @@ -610,8 +617,8 @@ describe.each([ beforeAll(async () => { const client = await getClient('Master') await clearAllIndexes(config) - const { uid } = await client.createIndex(index.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(index.uid) + await client.waitForTask(taskUid) }) test(`${permission} key: search on index and abort`, async () => { diff --git a/tests/searchable_attributes.test.ts b/tests/searchable_attributes.test.ts index a83b20444..b85cdb0d3 100644 --- a/tests/searchable_attributes.test.ts +++ b/tests/searchable_attributes.test.ts @@ -1,4 +1,4 @@ -import { ErrorStatusCode, EnqueuedTask } from '../src/types' +import { ErrorStatusCode } from '../src/types' import { clearAllIndexes, config, @@ -23,59 +23,58 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( ({ permission }) => { beforeEach(async () => { const client = await getClient('Master') - const { uid } = await client.index(index.uid).addDocuments(dataset) - await client.waitForTask(uid) - await client.index(index.uid).waitForTask(uid) + const { taskUid } = await client.index(index.uid).addDocuments(dataset) + await client.waitForTask(taskUid) }) test(`${permission} key: Get default searchable attributes`, async () => { const client = await getClient(permission) + const response: string[] = await client .index(index.uid) .getSearchableAttributes() + expect(response).toEqual(['*']) }) test(`${permission} key: Update searchable attributes`, async () => { const client = await getClient(permission) const newSearchableAttributes = ['title'] - const task: EnqueuedTask = await client + const task = await client .index(index.uid) .updateSearchableAttributes(newSearchableAttributes) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + await client.index(index.uid).waitForTask(task.taskUid) const response: string[] = await client .index(index.uid) .getSearchableAttributes() + expect(response).toEqual(newSearchableAttributes) }) test(`${permission} key: Update searchable attributes at null`, async () => { const client = await getClient(permission) - const task: EnqueuedTask = await client + const task = await client .index(index.uid) .updateSearchableAttributes(null) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + await client.index(index.uid).waitForTask(task.taskUid) const response: string[] = await client .index(index.uid) .getSearchableAttributes() + expect(response).toEqual(['*']) }) test(`${permission} key: Reset searchable attributes`, async () => { const client = await getClient(permission) - const task: EnqueuedTask = await client - .index(index.uid) - .resetSearchableAttributes() - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + const task = await client.index(index.uid).resetSearchableAttributes() + await client.index(index.uid).waitForTask(task.taskUid) const response: string[] = await client .index(index.uid) .getSearchableAttributes() + expect(response).toEqual(['*']) }) } @@ -86,8 +85,8 @@ describe.each([{ permission: 'Public' }])( ({ permission }) => { beforeEach(async () => { const client = await getClient('Master') - const { uid } = await client.createIndex(index.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(index.uid) + await client.waitForTask(taskUid) }) test(`${permission} key: try to get searchable attributes and be denied`, async () => { @@ -118,8 +117,8 @@ describe.each([{ permission: 'No' }])( ({ permission }) => { beforeAll(async () => { const client = await getClient('Master') - const { uid } = await client.createIndex(index.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(index.uid) + await client.waitForTask(taskUid) }) test(`${permission} key: try to get searchable attributes and be denied`, async () => { diff --git a/tests/settings.test.ts b/tests/settings.test.ts index 8b8cc3914..0eb327548 100644 --- a/tests/settings.test.ts +++ b/tests/settings.test.ts @@ -1,4 +1,4 @@ -import { ErrorStatusCode, EnqueuedTask, Settings } from '../src/types' +import { ErrorStatusCode } from '../src/types' import { clearAllIndexes, config, @@ -50,6 +50,12 @@ const defaultSettings = { disableOnWords: [], disableOnAttributes: [], }, + pagination: { + maxTotalHits: 1000, + }, + faceting: { + maxValuesPerFacet: 100, + }, } jest.setTimeout(100 * 1000) @@ -64,14 +70,14 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( beforeEach(async () => { await clearAllIndexes(config) const client = await getClient('Master') - const { uid: AddDocPkTask } = await client + const { taskUid: AddDocPkTask } = await client .index(indexAndPK.uid) .addDocuments(dataset, { primaryKey: indexAndPK.primaryKey, }) await client.waitForTask(AddDocPkTask) - const { uid: AddDocTask } = await client + const { taskUid: AddDocTask } = await client .index(index.uid) .addDocuments(dataset, {}) await client.waitForTask(AddDocTask) @@ -79,7 +85,9 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: Get default settings of an index`, async () => { const client = await getClient(permission) - const response: Settings = await client.index(index.uid).getSettings() + + const response = await client.index(index.uid).getSettings() + expect(response).toHaveProperty('rankingRules', defaultRankingRules) expect(response).toHaveProperty('distinctAttribute', null) expect(response).toHaveProperty('searchableAttributes', ['*']) @@ -91,9 +99,9 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: Get default settings of empty index with primary key`, async () => { const client = await getClient(permission) - const response: Settings = await client - .index(indexAndPK.uid) - .getSettings() + + const response = await client.index(indexAndPK.uid).getSettings() + expect(response).toHaveProperty('rankingRules', defaultRankingRules) expect(response).toHaveProperty('distinctAttribute', null) expect(response).toHaveProperty('searchableAttributes', ['*']) @@ -123,16 +131,19 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( disableOnWords: ['prince'], disableOnAttributes: ['comment'], }, + pagination: { + maxTotalHits: 1000, + }, + faceting: { + maxValuesPerFacet: 100, + }, } // Add the settings - const task: EnqueuedTask = await client - .index(index.uid) - .updateSettings(newSettings) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + const task = await client.index(index.uid).updateSettings(newSettings) + await client.index(index.uid).waitForTask(task.taskUid) // Fetch the settings - const response: Settings = await client.index(index.uid).getSettings() + const response = await client.index(index.uid).getSettings() // tests expect(response).toEqual(newSettings) @@ -160,14 +171,11 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( }, } // Add the settings - const task: EnqueuedTask = await client - .index(index.uid) - .updateSettings(newSettings) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + const task = await client.index(index.uid).updateSettings(newSettings) + await client.index(index.uid).waitForTask(task.taskUid) // Fetch the settings - const response: Settings = await client.index(index.uid).getSettings() + const response = await client.index(index.uid).getSettings() // tests expect(response).toEqual(defaultSettings) @@ -180,16 +188,13 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( rankingRules: ['title:asc', 'typo'], stopWords: ['the'], } - - const task: EnqueuedTask = await client + const task = await client .index(indexAndPK.uid) .updateSettings(newSettings) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(indexAndPK.uid).waitForTask(task.uid) + await client.index(indexAndPK.uid).waitForTask(task.taskUid) + + const response = await client.index(indexAndPK.uid).getSettings() - const response: Settings = await client - .index(indexAndPK.uid) - .getSettings() expect(response).toHaveProperty('rankingRules', newSettings.rankingRules) expect(response).toHaveProperty( 'distinctAttribute', @@ -203,11 +208,11 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: Reset settings`, async () => { const client = await getClient(permission) - const task: EnqueuedTask = await client.index(index.uid).resetSettings() - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + const task = await client.index(index.uid).resetSettings() + await client.index(index.uid).waitForTask(task.taskUid) + + const response = await client.index(index.uid).getSettings() - const response: Settings = await client.index(index.uid).getSettings() expect(response).toHaveProperty('rankingRules', defaultRankingRules) expect(response).toHaveProperty('distinctAttribute', null) expect(response).toHaveProperty('searchableAttributes', ['*']) @@ -219,15 +224,11 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: Reset settings of empty index`, async () => { const client = await getClient(permission) - const task: EnqueuedTask = await client - .index(indexAndPK.uid) - .resetSettings() - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + const task = await client.index(indexAndPK.uid).resetSettings() + await client.index(index.uid).waitForTask(task.taskUid) + + const response = await client.index(indexAndPK.uid).getSettings() - const response: Settings = await client - .index(indexAndPK.uid) - .getSettings() expect(response).toHaveProperty('rankingRules', defaultRankingRules) expect(response).toHaveProperty('distinctAttribute', null) expect(response).toHaveProperty('searchableAttributes', ['*']) @@ -241,13 +242,11 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( const newSettings = { searchableAttributes: ['title'], } - const task: EnqueuedTask = await client - .index(index.uid) - .updateSettings(newSettings) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + const task = await client.index(index.uid).updateSettings(newSettings) + await client.index(index.uid).waitForTask(task.taskUid) + + const response = await client.index(index.uid).getSettings() - const response: Settings = await client.index(index.uid).getSettings() expect(response).toHaveProperty('rankingRules', defaultRankingRules) expect(response).toHaveProperty( 'distinctAttribute', @@ -268,24 +267,20 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( searchableAttributes: ['title'], } // Update settings - const task: EnqueuedTask = await client + const task = await client .index(indexAndPK.uid) .updateSettings(newSettings) // Wait for setting addition to be done - await client.index(index.uid).waitForTask(task.uid) + await client.index(index.uid).waitForTask(task.taskUid) // Fetch settings - const response: Settings = await client - .index(indexAndPK.uid) - .getSettings() + const response = await client.index(indexAndPK.uid).getSettings() // Compare searchableAttributes expect(response).toHaveProperty( 'searchableAttributes', newSettings.searchableAttributes ) - - expect(task).toHaveProperty('uid', expect.any(Number)) expect(response).toHaveProperty('rankingRules', defaultRankingRules) expect(response).toHaveProperty( 'distinctAttribute', diff --git a/tests/sortable_attributes.test.ts b/tests/sortable_attributes.test.ts index ce99c18d4..20be4f135 100644 --- a/tests/sortable_attributes.test.ts +++ b/tests/sortable_attributes.test.ts @@ -1,4 +1,4 @@ -import { ErrorStatusCode, EnqueuedTask } from '../src/types' +import { ErrorStatusCode } from '../src/types' import { clearAllIndexes, config, @@ -23,10 +23,10 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( ({ permission }) => { beforeEach(async () => { const client = await getClient('Master') - const { uid } = await client.createIndex(index.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(index.uid) + await client.waitForTask(taskUid) - const { uid: docTask } = await client + const { taskUid: docTask } = await client .index(index.uid) .addDocuments(dataset) await client.waitForTask(docTask) @@ -34,52 +34,41 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( test(`${permission} key: Get default sortable attributes`, async () => { const client = await getClient(permission) - const response: string[] = await client - .index(index.uid) - .getSortableAttributes() + + const response = await client.index(index.uid).getSortableAttributes() + expect(response).toEqual([]) }) test(`${permission} key: Update sortable attributes`, async () => { const client = await getClient(permission) const newSortableAttributes = ['title'] - const task: EnqueuedTask = await client + const task = await client .index(index.uid) .updateSortableAttributes(newSortableAttributes) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + await client.index(index.uid).waitForTask(task.taskUid) - const response: string[] = await client - .index(index.uid) - .getSortableAttributes() + const response = await client.index(index.uid).getSortableAttributes() expect(response).toEqual(newSortableAttributes) }) test(`${permission} key: Update sortable attributes at null`, async () => { const client = await getClient(permission) - const task: EnqueuedTask = await client - .index(index.uid) - .updateSortableAttributes(null) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + const task = await client.index(index.uid).updateSortableAttributes(null) + await client.index(index.uid).waitForTask(task.taskUid) + + const response = await client.index(index.uid).getSortableAttributes() - const response: string[] = await client - .index(index.uid) - .getSortableAttributes() expect(response).toEqual([]) }) test(`${permission} key: Reset sortable attributes`, async () => { const client = await getClient(permission) - const task: EnqueuedTask = await client - .index(index.uid) - .resetSortableAttributes() - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + const task = await client.index(index.uid).resetSortableAttributes() + await client.index(index.uid).waitForTask(task.taskUid) + + const response = await client.index(index.uid).getSortableAttributes() - const response: string[] = await client - .index(index.uid) - .getSortableAttributes() expect(response).toEqual([]) }) } @@ -90,8 +79,8 @@ describe.each([{ permission: 'Public' }])( ({ permission }) => { beforeEach(async () => { const client = await getClient('Master') - const { uid } = await client.createIndex(index.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(index.uid) + await client.waitForTask(taskUid) }) test(`${permission} key: try to get sortable attributes and be denied`, async () => { @@ -122,8 +111,8 @@ describe.each([{ permission: 'No' }])( ({ permission }) => { beforeAll(async () => { const client = await getClient('Master') - const { uid } = await client.createIndex(index.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(index.uid) + await client.waitForTask(taskUid) }) test(`${permission} key: try to get sortable attributes and be denied`, async () => { diff --git a/tests/stop_words.test.ts b/tests/stop_words.test.ts index ed8b6cf9b..1f2438e2f 100644 --- a/tests/stop_words.test.ts +++ b/tests/stop_words.test.ts @@ -23,14 +23,14 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( ({ permission }) => { beforeEach(async () => { const client = await getClient('Master') - - const { uid } = await client.index(index.uid).addDocuments(dataset) - await client.waitForTask(uid) + const { taskUid } = await client.index(index.uid).addDocuments(dataset) + await client.waitForTask(taskUid) }) test(`${permission} key: Get default stop words`, async () => { const client = await getClient(permission) const response: string[] = await client.index(index.uid).getStopWords() + expect(response).toEqual([]) }) @@ -40,10 +40,10 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( const task: EnqueuedTask = await client .index(index.uid) .updateStopWords(newStopWords) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + await client.index(index.uid).waitForTask(task.taskUid) const response: string[] = await client.index(index.uid).getStopWords() + expect(response).toEqual(newStopWords) }) @@ -53,20 +53,20 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( const task: EnqueuedTask = await client .index(index.uid) .updateStopWords(newStopWords) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + await client.index(index.uid).waitForTask(task.taskUid) const response: string[] = await client.index(index.uid).getStopWords() + expect(response).toEqual([]) }) test(`${permission} key: Reset stop words`, async () => { const client = await getClient(permission) const task: EnqueuedTask = await client.index(index.uid).resetStopWords() - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + await client.index(index.uid).waitForTask(task.taskUid) const response: string[] = await client.index(index.uid).getStopWords() + expect(response).toEqual([]) }) } diff --git a/tests/synonyms.test.ts b/tests/synonyms.test.ts index a616d06e4..6a5b593e2 100644 --- a/tests/synonyms.test.ts +++ b/tests/synonyms.test.ts @@ -1,4 +1,4 @@ -import { ErrorStatusCode, EnqueuedTask } from '../src/types' +import { ErrorStatusCode } from '../src/types' import { clearAllIndexes, config, @@ -23,49 +23,48 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( ({ permission }) => { beforeEach(async () => { const client = await getClient('Master') - const { uid } = await client.index(index.uid).addDocuments(dataset) - await client.waitForTask(uid) + const { taskUid } = await client.index(index.uid).addDocuments(dataset) + await client.waitForTask(taskUid) }) + test(`${permission} key: Get default synonyms`, async () => { const client = await getClient(permission) const response: object = await client.index(index.uid).getSynonyms() + expect(response).toEqual({}) }) + test(`${permission} key: Update synonyms`, async () => { const client = await getClient(permission) const newSynonyms = { hp: ['harry potter'], } - const task: EnqueuedTask = await client - .index(index.uid) - .updateSynonyms(newSynonyms) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.waitForTask(task.uid) + const task = await client.index(index.uid).updateSynonyms(newSynonyms) + await client.waitForTask(task.taskUid) const response: object = await client.index(index.uid).getSynonyms() + expect(response).toEqual(newSynonyms) }) test(`${permission} key: Update synonyms with null value`, async () => { const client = await getClient(permission) const newSynonyms = null - const task: EnqueuedTask = await client - .index(index.uid) - .updateSynonyms(newSynonyms) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.waitForTask(task.uid) + const task = await client.index(index.uid).updateSynonyms(newSynonyms) + await client.waitForTask(task.taskUid) const response: object = await client.index(index.uid).getSynonyms() + expect(response).toEqual({}) }) test(`${permission} key: Reset synonyms`, async () => { const client = await getClient(permission) - const task: EnqueuedTask = await client.index(index.uid).resetSynonyms() - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.waitForTask(task.uid) + const task = await client.index(index.uid).resetSynonyms() + await client.waitForTask(task.taskUid) const response: object = await client.index(index.uid).getSynonyms() + expect(response).toEqual({}) }) } diff --git a/tests/task.test.ts b/tests/task.test.ts index d5fe8bc10..7af51931f 100644 --- a/tests/task.test.ts +++ b/tests/task.test.ts @@ -1,4 +1,4 @@ -import { ErrorStatusCode, EnqueuedTask, Task, TaskStatus } from '../src/types' +import { ErrorStatusCode, TaskTypes, TaskStatus } from '../src/types' import { clearAllIndexes, config, @@ -12,6 +12,14 @@ const index = { uid: 'movies_test', } +const index2 = { + uid: 'movies_test2', +} + +const index3 = { + uid: 'movies_test2', +} + jest.setTimeout(100 * 1000) afterAll(() => { @@ -19,128 +27,228 @@ afterAll(() => { }) describe.each([{ permission: 'Master' }, { permission: 'Private' }])( - 'Test on updates', + 'Tests on tasks', ({ permission }) => { beforeEach(async () => { const client = await getClient('Master') - const { uid } = await client.createIndex(index.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(index.uid) + await client.waitForTask(taskUid) }) test(`${permission} key: Get one enqueued task`, async () => { const client = await getClient(permission) - const response: EnqueuedTask = await client - .index(index.uid) - .addDocuments(dataset) - expect(response).toHaveProperty('uid', expect.any(Number)) - expect(response).toHaveProperty('indexUid', index.uid) - expect(response).toHaveProperty('status') - expect(response).toHaveProperty('type', 'documentAddition') - expect(response).toHaveProperty('enqueuedAt') - await client.waitForTask(response.uid) - - const stausReponse: Task = await client - .index(index.uid) - .getTask(response.uid) - - expect(stausReponse).toHaveProperty('status', TaskStatus.TASK_SUCCEEDED) - expect(stausReponse).toHaveProperty('uid', expect.any(Number)) - expect(stausReponse).toHaveProperty('type', 'documentAddition') - expect(stausReponse).toHaveProperty('details') - expect(stausReponse.details).toHaveProperty('indexedDocuments', 7) - expect(stausReponse.details).toHaveProperty('receivedDocuments', 7) - expect(stausReponse).toHaveProperty('duration', expect.any(String)) - expect(stausReponse).toHaveProperty('enqueuedAt', expect.any(String)) - expect(stausReponse).toHaveProperty('finishedAt', expect.any(String)) - expect(stausReponse).toHaveProperty('startedAt', expect.any(String)) + + const enqueuedTask = await client.index(index.uid).addDocuments(dataset) + + expect(enqueuedTask.taskUid).toBeDefined() + expect(enqueuedTask.indexUid).toEqual(index.uid) + expect(enqueuedTask.status).toBeDefined() + expect(enqueuedTask.type).toEqual(TaskTypes.DOCUMENTS_ADDITION_OR_UPDATE) + expect(enqueuedTask.enqueuedAt).toBeDefined() }) - test(`${permission} key: Get one update`, async () => { + test(`${permission} key: Get one task`, async () => { const client = await getClient(permission) - const response: EnqueuedTask = await client - .index(index.uid) - .addDocuments(dataset) - expect(response).toHaveProperty('uid', expect.any(Number)) - await client.waitForTask(response.uid) + const enqueuedTask = await client.index(index.uid).addDocuments(dataset) + await client.waitForTask(enqueuedTask.taskUid) + + const task = await client.getTask(enqueuedTask.taskUid) + + expect(task.indexUid).toEqual(index.uid) + expect(task.status).toEqual(TaskStatus.TASK_SUCCEEDED) + expect(task.type).toEqual(TaskTypes.DOCUMENTS_ADDITION_OR_UPDATE) + expect(task.enqueuedAt).toBeDefined() + expect(task.uid).toEqual(enqueuedTask.taskUid) + expect(task).toHaveProperty('details') + expect(task.details.indexedDocuments).toEqual(7) + expect(task.details.receivedDocuments).toEqual(7) + expect(task.duration).toBeDefined() + expect(task.enqueuedAt).toBeDefined() + expect(task.finishedAt).toBeDefined() + expect(task.startedAt).toBeDefined() + }) + + test(`${permission} key: Get one task with index instance`, async () => { + const client = await getClient(permission) + const enqueuedTask = await client.index(index.uid).addDocuments(dataset) + await client.waitForTask(enqueuedTask.taskUid) + + const task = await client.index(index.uid).getTask(enqueuedTask.taskUid) + + expect(task.indexUid).toEqual(index.uid) + expect(task.uid).toEqual(enqueuedTask.taskUid) + }) - const stausReponse: Task = await client + test(`${permission} key: Get all tasks`, async () => { + const client = await getClient(permission) + const enqueuedTask = await client .index(index.uid) - .getTask(response.uid) - - expect(stausReponse).toHaveProperty('status', TaskStatus.TASK_SUCCEEDED) - expect(stausReponse).toHaveProperty('uid', expect.any(Number)) - expect(stausReponse).toHaveProperty('type', 'documentAddition') - expect(stausReponse).toHaveProperty('details') - expect(stausReponse.details).toHaveProperty('indexedDocuments', 7) - expect(stausReponse.details).toHaveProperty('receivedDocuments', 7) - expect(stausReponse).toHaveProperty('duration', expect.any(String)) - expect(stausReponse).toHaveProperty('enqueuedAt', expect.any(String)) - expect(stausReponse).toHaveProperty('finishedAt', expect.any(String)) - expect(stausReponse).toHaveProperty('startedAt', expect.any(String)) + .addDocuments([{ id: 1 }]) + await client.waitForTask(enqueuedTask.taskUid) + + const tasks = await client.getTasks() + + expect(tasks.results).toBeInstanceOf(Array) + expect(tasks.results[0].uid).toEqual(enqueuedTask.taskUid) }) - test(`${permission} key: Get all updates`, async () => { + test(`${permission} key: Get all tasks with type filter`, async () => { const client = await getClient(permission) - const { uid } = await client.index(index.uid).addDocuments([{ id: 1 }]) - await client.waitForTask(uid) + await client.index(index.uid).addDocuments([{ id: 1 }]) + await client.index(index.uid).deleteDocument(1) + await client.createIndex(index2.uid) + + const tasks = await client.getTasks({ + type: [ + TaskTypes.DOCUMENTS_ADDITION_OR_UPDATE, + TaskTypes.DOCUMENT_DELETION, + ], + }) + const onlyDocumentAddition = new Set( + tasks.results.map((task) => task.type) + ) + + expect(onlyDocumentAddition.size).toEqual(2) + }) - const response = await client.index(index.uid).getTasks() + test(`${permission} key: Get all tasks with type filter on an index`, async () => { + const client = await getClient(permission) + await client.deleteIndex(index2.uid) + await client.createIndex(index2.uid) + await client.index(index.uid).addDocuments([{ id: 1 }]) + await client.index(index2.uid).addDocuments([{ id: 1 }]) + await client.index(index2.uid).deleteDocument(1) - expect(response.results[0]).toHaveProperty( - 'status', - TaskStatus.TASK_SUCCEEDED + const tasks = await client.index(index.uid).getTasks({ + type: [ + TaskTypes.DOCUMENTS_ADDITION_OR_UPDATE, + TaskTypes.DOCUMENT_DELETION, + ], + }) + const onlyDocumentAddition = new Set( + tasks.results.map((task) => task.type) ) - expect(response.results[0]).toHaveProperty('uid', expect.any(Number)) - expect(response.results[0].type).toEqual('documentAddition') - expect(response.results[0]).toHaveProperty('duration', expect.any(String)) - expect(response.results[0]).toHaveProperty( - 'enqueuedAt', - expect.any(String) + + expect(onlyDocumentAddition.size).toEqual(2) + }) + + test(`${permission} key: Get all tasks with pagination`, async () => { + const client = await getClient(permission) + const task1 = await client.index(index.uid).addDocuments([{ id: 1 }]) + const task2 = await client.index(index.uid).addDocuments([{ id: 1 }]) + await client.waitForTask(task1.taskUid) + await client.waitForTask(task2.taskUid) + + const tasks = await client.getTasks({ from: 1, limit: 1 }) + + expect(tasks.results.length).toEqual(1) + expect(tasks.from).toEqual(1) + expect(tasks.limit).toEqual(1) + expect(tasks.next).toEqual(0) + }) + + test(`${permission} key: Get all tasks with status filter`, async () => { + const client = await getClient(permission) + const task1 = await client.index(index.uid).addDocuments([{ id: 1 }]) + const task2 = await client.index(index.uid).addDocuments([{}]) + await client.waitForTask(task1.taskUid) + await client.waitForTask(task2.taskUid) + + const tasks = await client.getTasks({ + status: [TaskStatus.TASK_SUCCEEDED, TaskStatus.TASK_FAILED], + }) + const onlySuccesfullTasks = new Set( + tasks.results.map((task) => task.status) ) - expect(response.results[0]).toHaveProperty( - 'finishedAt', - expect.any(String) + + expect(onlySuccesfullTasks.size).toEqual(2) + }) + + test(`${permission} key: Get all tasks with status filter on an index`, async () => { + const client = await getClient(permission) + const task1 = await client.index(index.uid).addDocuments([{ id: 1 }]) + const task2 = await client.index(index.uid).addDocuments([{}]) + const task3 = await client.index(index2.uid).addDocuments([{}]) + await client.waitForTask(task1.taskUid) + await client.waitForTask(task2.taskUid) + await client.waitForTask(task3.taskUid) + + const tasks = await client.index(index.uid).getTasks({ + status: [TaskStatus.TASK_SUCCEEDED, TaskStatus.TASK_FAILED], + }) + const onlySuccesfullTasks = new Set( + tasks.results.map((task) => task.status) ) - expect(response.results[0]).toHaveProperty( - 'startedAt', - expect.any(String) + const onlyTaskWithSameUid = new Set( + tasks.results.map((task) => task.indexUid) ) + + expect(onlySuccesfullTasks.size).toEqual(2) + expect(onlyTaskWithSameUid.size).toEqual(1) }) - test(`${permission} key: Try to get update that does not exist`, async () => { + test(`${permission} key: Get all tasks with indexUid filter`, async () => { const client = await getClient(permission) - await expect( - client.index(index.uid).getTask(2545) - ).rejects.toHaveProperty('code', ErrorStatusCode.TASK_NOT_FOUND) + await client.index(index.uid).addDocuments([{ id: 1 }]) + await client.index(index2.uid).addDocuments([{ id: 1 }]) + await client.index(index3.uid).addDocuments([{ id: 1 }]) + + const tasks = await client.getTasks({ + indexUid: [index.uid, index2.uid], + }) + const onlyTaskWithSameUid = new Set( + tasks.results.map((task) => task.indexUid) + ) + + expect(onlyTaskWithSameUid.size).toEqual(2) }) - } -) -describe.each([{ permission: 'Public' }])( - 'Test on updates', - ({ permission }) => { - beforeEach(async () => { - await clearAllIndexes(config) + test(`${permission} key: Get all indexes tasks with index instance`, async () => { + const client = await getClient(permission) + await client.index(index.uid).addDocuments([{ id: 1 }]) + await client.index(index2.uid).addDocuments([{ id: 1 }]) + + const tasks = await client.index(index.uid).getTasks() + const onlyTaskWithSameUid = new Set( + tasks.results.map((task) => task.indexUid) + ) + + expect(onlyTaskWithSameUid.size).toEqual(1) }) - test(`${permission} key: Try to get a update and be denied`, async () => { + test(`${permission} key: Try to get a task that does not exist`, async () => { const client = await getClient(permission) - await expect(client.index(index.uid).getTask(0)).rejects.toHaveProperty( + + await expect(client.getTask(254500)).rejects.toHaveProperty( 'code', - ErrorStatusCode.INVALID_API_KEY + ErrorStatusCode.TASK_NOT_FOUND ) }) } ) -describe.each([{ permission: 'No' }])('Test on updates', ({ permission }) => { +describe.each([{ permission: 'Public' }])('Test on tasks', ({ permission }) => { + beforeEach(async () => { + await clearAllIndexes(config) + }) + + test(`${permission} key: Try to get a task and be denied`, async () => { + const client = await getClient(permission) + await expect(client.getTask(0)).rejects.toHaveProperty( + 'code', + ErrorStatusCode.INVALID_API_KEY + ) + }) +}) + +describe.each([{ permission: 'No' }])('Test on tasks', ({ permission }) => { beforeEach(async () => { await clearAllIndexes(config) }) - test(`${permission} key: Try to get an update and be denied`, async () => { + test(`${permission} key: Try to get an task and be denied`, async () => { const client = await getClient(permission) - await expect(client.index(index.uid).getTask(0)).rejects.toHaveProperty( + await expect(client.getTask(0)).rejects.toHaveProperty( 'code', ErrorStatusCode.MISSING_AUTHORIZATION_HEADER ) @@ -151,11 +259,12 @@ describe.each([ { host: BAD_HOST, trailing: false }, { host: `${BAD_HOST}/api`, trailing: false }, { host: `${BAD_HOST}/trailing/`, trailing: true }, -])('Tests on url construction', ({ host, trailing }) => { - test(`Test getUpdateStatus route`, async () => { - const route = `indexes/${index.uid}/tasks/1` +])('Tests on task url construction', ({ host, trailing }) => { + test(`Test on getTask route`, async () => { + const route = `tasks/1` const client = new MeiliSearch({ host }) const strippedHost = trailing ? host.slice(0, -1) : host + await expect(client.index(index.uid).getTask(1)).rejects.toHaveProperty( 'message', `request to ${strippedHost}/${route} failed, reason: connect ECONNREFUSED ${BAD_HOST.replace( @@ -165,10 +274,11 @@ describe.each([ ) }) - test(`Test getAllUpdateStatus route`, async () => { - const route = `indexes/${index.uid}/tasks` + test(`Test on getTasks route`, async () => { + const route = `tasks?indexUid=movies_test` const client = new MeiliSearch({ host }) const strippedHost = trailing ? host.slice(0, -1) : host + await expect(client.index(index.uid).getTasks()).rejects.toHaveProperty( 'message', `request to ${strippedHost}/${route} failed, reason: connect ECONNREFUSED ${BAD_HOST.replace( diff --git a/tests/token.test.ts b/tests/token.test.ts index 901d61771..63f06f035 100644 --- a/tests/token.test.ts +++ b/tests/token.test.ts @@ -9,6 +9,7 @@ import { } from './utils/meilisearch-test-utils' import crypto from 'crypto' import MeiliSearch from '../src' +import { MeiliSearchError } from '../src/errors' const HASH_ALGORITHM = 'HS256' const TOKEN_TYP = 'JWT' @@ -24,13 +25,26 @@ describe.each([{ permission: 'Private' }])( beforeEach(async () => { const client = await getClient('Master') await client.index(UID).delete() - const { uid } = await client.index(UID).addDocuments(dataset) - await client.waitForTask(uid) + const { taskUid } = await client.index(UID).addDocuments(dataset) + await client.waitForTask(taskUid) + + const keys = await client.getKeys() + + const customKeys = keys.results.filter( + (key) => + key.name !== 'Default Search API Key' && + key.name !== 'Default Admin API Key' + ) + + // Delete all custom keys + await Promise.all(customKeys.map((key) => client.deleteKey(key.uid))) }) test(`${permission} key: create a tenant token and test header`, async () => { const client = await getClient(permission) - const token = client.generateTenantToken([]) + const apiKey = await getKey(permission) + const { uid } = await client.getKey(apiKey) + const token = client.generateTenantToken(uid, [], {}) const [header64] = token.split('.') // header @@ -41,8 +55,9 @@ describe.each([{ permission: 'Private' }])( test(`${permission} key: create a tenant token and test signature`, async () => { const client = await getClient(permission) - const token = client.generateTenantToken([]) const apiKey = await getKey(permission) + const { uid } = await client.getKey(apiKey) + const token = client.generateTenantToken(uid, [], {}) const [header64, payload64, signature64] = token.split('.') // signature @@ -59,46 +74,54 @@ describe.each([{ permission: 'Private' }])( test(`${permission} key: create a tenant token with default values and test payload`, async () => { const client = await getClient(permission) - const token = client.generateTenantToken([]) const apiKey = await getKey(permission) + const { uid } = await client.getKey(apiKey) + const token = client.generateTenantToken(uid, [], {}) const [_, payload64] = token.split('.') // payload - const { apiKeyPrefix, exp, searchRules } = JSON.parse(decode64(payload64)) - expect(apiKeyPrefix).toEqual(apiKey.substring(0, 8)) + const { apiKeyUid, exp, searchRules } = JSON.parse(decode64(payload64)) + + expect(apiKeyUid).toEqual(uid) expect(exp).toBeUndefined() expect(searchRules).toEqual([]) }) test(`${permission} key: create a tenant token with array searchRules and test payload`, async () => { const client = await getClient(permission) - const token = client.generateTenantToken([UID]) const apiKey = await getKey(permission) + const { uid } = await client.getKey(apiKey) + const token = client.generateTenantToken(uid, [UID]) const [_, payload64] = token.split('.') // payload - const { apiKeyPrefix, exp, searchRules } = JSON.parse(decode64(payload64)) - expect(apiKeyPrefix).toEqual(apiKey.substring(0, 8)) + const { apiKeyUid, exp, searchRules } = JSON.parse(decode64(payload64)) + + expect(apiKeyUid).toEqual(uid) expect(exp).toBeUndefined() expect(searchRules).toEqual([UID]) }) test(`${permission} key: create a tenant token with oject search rules and test payload`, async () => { const client = await getClient(permission) - const token = client.generateTenantToken({ [UID]: {} }) const apiKey = await getKey(permission) + const { uid } = await client.getKey(apiKey) + const token = client.generateTenantToken(uid, { [UID]: {} }) const [_, payload64] = token.split('.') // payload - const { apiKeyPrefix, exp, searchRules } = JSON.parse(decode64(payload64)) - expect(apiKeyPrefix).toEqual(apiKey.substring(0, 8)) + const { apiKeyUid, exp, searchRules } = JSON.parse(decode64(payload64)) + expect(apiKeyUid).toEqual(uid) expect(exp).toBeUndefined() expect(searchRules).toEqual({ [UID]: {} }) }) test(`${permission} key: Search in tenant token with wildcard`, async () => { const client = await getClient(permission) - const token = client.generateTenantToken(['*']) + const apiKey = await getKey(permission) + const { uid } = await client.getKey(apiKey) + + const token = client.generateTenantToken(uid, ['*']) const searchClient = new MeiliSearch({ host: HOST, apiKey: token }) @@ -107,51 +130,48 @@ describe.each([{ permission: 'Private' }])( }) test(`${permission} key: Search in tenant token with custom api key`, async () => { - // add filterable const masterClient = await getClient('master') - const { key } = await masterClient.createKey({ + const { uid, key } = await masterClient.createKey({ expiresAt: null, description: 'Custom key', actions: ['search'], indexes: [UID], }) - const client = await getClient(permission) - const token = client.generateTenantToken(['*'], { apiKey: key }) + const token = client.generateTenantToken(uid, ['*'], { + apiKey: key, + }) const searchClient = new MeiliSearch({ host: HOST, apiKey: token }) // search - expect(searchClient.index(UID).search()).resolves.not.toBeUndefined() - }) - - test(`${permission} key: create a tenant token no api key and test payload`, () => { - const client = new MeiliSearch({ host: HOST }) - // Needs to be wrapped in a function for it to work. - expect(() => client.generateTenantToken([])).toThrow() + expect(searchClient.index(UID).search()).resolves.toBeDefined() }) test(`${permission} key: Search in tenant token with expireAt`, async () => { const client = await getClient(permission) const date = new Date('December 17, 4000 03:24:00') - const token = client.generateTenantToken(['*'], { + const apiKey = await getKey(permission) + const { uid } = await client.getKey(apiKey) + const token = client.generateTenantToken(uid, ['*'], { expiresAt: date, }) const [_, payload] = token.split('.') - expect(JSON.parse(decode64(payload)).exp).toEqual(date.getTime()) - const searchClient = new MeiliSearch({ host: HOST, apiKey: token }) - // search + expect(JSON.parse(decode64(payload)).exp).toEqual(date.getTime()) expect(searchClient.index(UID).search()).resolves.not.toBeUndefined() }) test(`${permission} key: Search in tenant token with expireAt value set in the past`, async () => { const client = await getClient(permission) + const apiKey = await getKey(permission) + const { uid } = await client.getKey(apiKey) const date = new Date('December 17, 2000 03:24:00') + expect(() => - client.generateTenantToken(['*'], { + client.generateTenantToken(uid, ['*'], { expiresAt: date, }) ).toThrow() @@ -159,9 +179,12 @@ describe.each([{ permission: 'Private' }])( test(`${permission} key: Search in tenant token with specific index set to null`, async () => { const client = await getClient(permission) - const token = client.generateTenantToken({ + const apiKey = await getKey(permission) + const { uid } = await client.getKey(apiKey) + const token = client.generateTenantToken(uid, { [UID]: null, }) + const searchClient = new MeiliSearch({ host: HOST, apiKey: token }) // search @@ -171,24 +194,28 @@ describe.each([{ permission: 'Private' }])( test(`${permission} key: Search in tenant token with specific index and specific rules`, async () => { // add filterable const masterClient = await getClient('master') - const { uid } = await masterClient + const { taskUid } = await masterClient .index(UID) .updateFilterableAttributes(['id']) - await masterClient.waitForTask(uid) - + await masterClient.waitForTask(taskUid) const client = await getClient(permission) - const token = client.generateTenantToken({ + const apiKey = await getKey(permission) + const { uid } = await client.getKey(apiKey) + const token = client.generateTenantToken(uid, { [UID]: { filter: 'id = 2' }, }) + const searchClient = new MeiliSearch({ host: HOST, apiKey: token }) // search expect(searchClient.index(UID).search()).resolves.not.toBeUndefined() }) - test(`${permission} key: Search in tenant token with empty array `, async () => { + test(`${permission} key: Search in tenant token with empty array throws an error`, async () => { const client = await getClient(permission) - const token = client.generateTenantToken([]) + const apiKey = await getKey(permission) + const { uid } = await client.getKey(apiKey) + const token = client.generateTenantToken(uid, []) const searchClient = new MeiliSearch({ host: HOST, apiKey: token }) @@ -200,7 +227,9 @@ describe.each([{ permission: 'Private' }])( test(`${permission} key: Search in tenant token on index with no permissions `, async () => { const client = await getClient(permission) - const token = client.generateTenantToken({ misc: null }) + const apiKey = await getKey(permission) + const { uid } = await client.getKey(apiKey) + const token = client.generateTenantToken(uid, { misc: null }) const searchClient = new MeiliSearch({ host: HOST, apiKey: token }) @@ -209,5 +238,46 @@ describe.each([{ permission: 'Private' }])( searchClient.index(UID).search('pride') ).rejects.toHaveProperty('code', 'invalid_api_key') }) + + test(`${permission} key: Creates tenant token with an expiration date in the past throws an error`, async () => { + const client = await getClient(permission) + const apiKey = await getKey(permission) + const { uid } = await client.getKey(apiKey) + const date = new Date('December 17, 2000 03:24:00') + + expect(() => + client.generateTenantToken( + uid, + {}, + { + expiresAt: date, + } + ) + ).toThrowError( + new MeiliSearchError( + `Meilisearch: The expiresAt field must be a date in the future.` + ) + ) + }) + + test(`${permission} key: Creates tenant token with wrong uid type throws an error`, async () => { + const client = await getClient(permission) + + expect(() => client.generateTenantToken('1234', ['*'])).toThrowError( + new MeiliSearchError( + `Meilisearch: The uid of your key is not a valid uuid4. To find out the uid of your key use getKey().` + ) + ) + }) + + test(`${permission} key: Creates a tenant token with no api key in client and in parameters throws an error`, () => { + const client = new MeiliSearch({ host: HOST }) + + expect(() => client.generateTenantToken('123', [])).toThrowError( + new MeiliSearchError( + `Meilisearch: The API key used for the token generation must exist and be of type string.` + ) + ) + }) } ) diff --git a/tests/typed_search.test.ts b/tests/typed_search.test.ts index 81bd8b5ca..542fbb505 100644 --- a/tests/typed_search.test.ts +++ b/tests/typed_search.test.ts @@ -89,18 +89,20 @@ describe.each([ await clearAllIndexes(config) const task1 = await client.createIndex(index.uid) - await client.waitForTask(task1.uid) + await client.waitForTask(task1.taskUid) const task2 = await client.createIndex(emptyIndex.uid) - await client.waitForTask(task2.uid) + await client.waitForTask(task2.taskUid) const newFilterableAttributes = ['genre', 'title'] - const response: EnqueuedTask = await client + const task: EnqueuedTask = await client .index(index.uid) .updateFilterableAttributes(newFilterableAttributes) - await client.waitForTask(response.uid) - const { uid } = await client.index(index.uid).addDocuments(dataset) - await client.waitForTask(uid) + await client.waitForTask(task.taskUid) + const { taskUid } = await client + .index(index.uid) + .addDocuments(dataset) + await client.waitForTask(taskUid) }) test(`${permission} key: Basic search`, async () => { @@ -161,17 +163,17 @@ describe.each([ filter: 'title = "Le Petit Prince"', attributesToCrop: ['*'], cropLength: 5, - matches: true, + showMatchesPosition: true, }) expect(response.hits.length === 1).toBeTruthy() expect(response.offset === 0).toBeTruthy() expect(response.limit === 20).toBeTruthy() expect(response).toHaveProperty('processingTimeMs', expect.any(Number)) expect(response.query === 'prince').toBeTruthy() - expect(response.hits[0]?._matchesInfo?.comment).toEqual([ + expect(response.hits[0]?._matchesPosition?.comment).toEqual([ { start: 22, length: 6 }, ]) - expect(response.hits[0]?._matchesInfo?.title).toEqual([ + expect(response.hits[0]?._matchesPosition?.title).toEqual([ { start: 9, length: 6 }, ]) }) @@ -186,7 +188,7 @@ describe.each([ cropLength: 6, attributesToHighlight: ['*'], filter: 'title = "Le Petit Prince"', - matches: true, + showMatchesPosition: true, }) expect(response.hits.length === 1).toBeTruthy() expect(response.offset === 0).toBeTruthy() @@ -203,7 +205,10 @@ describe.each([ expect(response.hits[0]._formatted).toHaveProperty('comment') expect(response.hits[0]._formatted).not.toHaveProperty('description') expect(response.hits.length === 1).toBeTruthy() - expect(response.hits[0]).toHaveProperty('_matchesInfo', expect.any(Object)) + expect(response.hits[0]).toHaveProperty( + '_matchesPosition', + expect.any(Object) + ) }) test(`${permission} key: Search with all options and all fields`, async () => { @@ -216,7 +221,7 @@ describe.each([ cropLength: 6, attributesToHighlight: ['*'], filter: 'title = "Le Petit Prince"', - matches: true, + showMatchesPosition: true, }) expect(response.hits.length === 1).toBeTruthy() expect(response.offset === 0).toBeTruthy() @@ -224,9 +229,11 @@ describe.each([ expect(response).toHaveProperty('processingTimeMs', expect.any(Number)) expect(response.query === 'prince').toBeTruthy() expect(response.hits[0]?.title === 'Le Petit Prince').toBeTruthy() - expect(response.hits[0]?._matchesInfo?.title?.[0]?.start === 9).toBeTruthy() expect( - response.hits[0]?._matchesInfo?.title?.[0]?.length === 6 + response.hits[0]?._matchesPosition?.title?.[0]?.start === 9 + ).toBeTruthy() + expect( + response.hits[0]?._matchesPosition?.title?.[0]?.length === 6 ).toBeTruthy() expect(response.hits[0]._formatted).toHaveProperty( 'title', @@ -244,7 +251,7 @@ describe.each([ cropLength: 6, attributesToHighlight: ['id', 'title'], filter: 'title = "Le Petit Prince"', - matches: true, + showMatchesPosition: true, }) expect(response.hits.length === 1).toBeTruthy() expect(response.offset === 0).toBeTruthy() @@ -258,7 +265,7 @@ describe.each([ // expect(response.hits[0].comment).toEqual('comment') expect(response.hits[0]?.title === 'Le Petit Prince').toBeTruthy() - expect(response.hits[0]?._matchesInfo?.title).toEqual([ + expect(response.hits[0]?._matchesPosition?.title).toEqual([ { start: 9, length: 6 }, ]) expect(response.hits[0]._formatted).toHaveProperty( @@ -292,14 +299,13 @@ describe.each([ expect(response.hits[0]._formatted?.isTrue).toEqual(true) }) - test(`${permission} key: Search with filter and facetsDistribution`, async () => { + test(`${permission} key: Search with filter and facets`, async () => { const client = await getClient(permission) const response = await client.index(index.uid).search('a', { filter: ['genre=romance'], - facetsDistribution: ['genre'], + facets: ['genre'], }) - expect(response.facetsDistribution?.genre?.romance === 2).toBeTruthy() - expect(response.exhaustiveFacetsCount === false).toBeTruthy() + expect(response.facetDistribution?.genre?.romance === 2).toBeTruthy() expect(response.hits.length === 2).toBeTruthy() }) @@ -316,10 +322,9 @@ describe.each([ const client = await getClient(permission) const response = await client.index(index.uid).search('a', { filter: ['genre=romance', ['genre=romance', 'genre=romance']], - facetsDistribution: ['genre'], + facets: ['genre'], }) - expect(response.facetsDistribution?.genre?.romance === 2).toBeTruthy() - expect(response.exhaustiveFacetsCount === false).toBeTruthy() + expect(response.facetDistribution?.genre?.romance === 2).toBeTruthy() expect(response.hits.length === 2).toBeTruthy() }) @@ -327,10 +332,9 @@ describe.each([ const client = await getClient(permission) const response = await client.index(index.uid).search(undefined, { filter: ['genre = fantasy'], - facetsDistribution: ['genre'], + facets: ['genre'], }) - expect(response.facetsDistribution?.genre?.fantasy === 2).toBeTruthy() - expect(response.exhaustiveFacetsCount === false).toBeTruthy() + expect(response.facetDistribution?.genre?.fantasy === 2).toBeTruthy() expect(response.hits.length === 2).toBeTruthy() }) @@ -338,10 +342,9 @@ describe.each([ const client = await getClient(permission) const response = await client.index(index.uid).search(null, { filter: ['genre = fantasy'], - facetsDistribution: ['genre'], + facets: ['genre'], }) - expect(response.facetsDistribution?.genre?.fantasy === 2).toBeTruthy() - expect(response.exhaustiveFacetsCount === false).toBeTruthy() + expect(response.facetDistribution?.genre?.fantasy === 2).toBeTruthy() expect(response.hits.length === 2).toBeTruthy() }) @@ -356,8 +359,9 @@ describe.each([ test(`${permission} key: Try to Search on deleted index and fail`, async () => { const client = await getClient(permission) const masterClient = await getClient('Master') - const { uid } = await masterClient.index(index.uid).delete() - await masterClient.waitForTask(uid) + const { taskUid } = await masterClient.index(index.uid).delete() + await masterClient.waitForTask(taskUid) + await expect( client.index(index.uid).search('prince') ).rejects.toHaveProperty('code', ErrorStatusCode.INDEX_NOT_FOUND) @@ -372,7 +376,7 @@ describe.each([{ permission: 'Master' }])( const client = await getClient('Master') await client.createIndex(index.uid) - const { uid: documentAdditionTask } = await client + const { taskUid: documentAdditionTask } = await client .index(index.uid) .addDocuments(datasetWithNests) await client.waitForTask(documentAdditionTask) @@ -390,7 +394,7 @@ describe.each([{ permission: 'Master' }])( test(`${permission} key: search on nested content with searchable on specific nested field`, async () => { const client = await getClient(permission) - const { uid: settingsUpdateTask }: EnqueuedTask = await client + const { taskUid: settingsUpdateTask }: EnqueuedTask = await client .index(index.uid) .updateSettings({ searchableAttributes: ['title', 'info.comment'], @@ -407,7 +411,7 @@ describe.each([{ permission: 'Master' }])( test(`${permission} key: search on nested content with sort`, async () => { const client = await getClient(permission) - const { uid: settingsUpdateTask }: EnqueuedTask = await client + const { taskUid: settingsUpdateTask }: EnqueuedTask = await client .index(index.uid) .updateSettings({ searchableAttributes: ['title', 'info.comment'], diff --git a/tests/typo_tolerance.test.ts b/tests/typo_tolerance.test.ts index afe8911e6..d41d93022 100644 --- a/tests/typo_tolerance.test.ts +++ b/tests/typo_tolerance.test.ts @@ -1,4 +1,4 @@ -import { ErrorStatusCode, EnqueuedTask } from '../src/types' +import { ErrorStatusCode } from '../src/types' import { clearAllIndexes, config, @@ -34,8 +34,8 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( beforeEach(async () => { await clearAllIndexes(config) const client = await getClient('master') - const { uid } = await client.index(index.uid).addDocuments(dataset) - await client.waitForTask(uid) + const { taskUid } = await client.index(index.uid).addDocuments(dataset) + await client.waitForTask(taskUid) }) test(`${permission} key: Get default typo tolerance settings`, async () => { @@ -57,43 +57,33 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( disableOnWords: ['title'], disableOnAttributes: ['hello'], } - const task: EnqueuedTask = await client + const task = await client .index(index.uid) .updateTypoTolerance(newTypoTolerance) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + await client.index(index.uid).waitForTask(task.taskUid) + + const response = await client.index(index.uid).getTypoTolerance() - const response: string[] = await client - .index(index.uid) - .getTypoTolerance() expect(response).toEqual(newTypoTolerance) }) test(`${permission} key: Update typo tolerance using null as value`, async () => { const client = await getClient(permission) - const task: EnqueuedTask = await client - .index(index.uid) - .updateTypoTolerance(null) - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + const task = await client.index(index.uid).updateTypoTolerance(null) + await client.index(index.uid).waitForTask(task.taskUid) + + const response = await client.index(index.uid).getTypoTolerance() - const response: string[] = await client - .index(index.uid) - .getTypoTolerance() expect(response).toEqual(defaultTypoTolerance) }) test(`${permission} key: Reset typo tolerance settings`, async () => { const client = await getClient(permission) - const task: EnqueuedTask = await client - .index(index.uid) - .resetTypoTolerance() - expect(task).toHaveProperty('uid', expect.any(Number)) - await client.index(index.uid).waitForTask(task.uid) + const task = await client.index(index.uid).resetTypoTolerance() + await client.index(index.uid).waitForTask(task.taskUid) + + const response = await client.index(index.uid).getTypoTolerance() - const response: string[] = await client - .index(index.uid) - .getTypoTolerance() expect(response).toEqual(defaultTypoTolerance) }) } diff --git a/tests/utils/meilisearch-test-utils.ts b/tests/utils/meilisearch-test-utils.ts index 8b843f643..174d3ae3d 100644 --- a/tests/utils/meilisearch-test-utils.ts +++ b/tests/utils/meilisearch-test-utils.ts @@ -1,9 +1,5 @@ -import { MeiliSearch, MeiliSearchTimeOutError, Index } from '../../src' -import { Config, EnqueuedDump } from '../../src/types' - -async function sleep(ms: number): Promise { - return await new Promise((resolve) => setTimeout(resolve, ms)) -} +import { MeiliSearch, Index } from '../../src' +import { Config } from '../../src/types' // testing const MASTER_KEY = 'masterKey' @@ -34,16 +30,14 @@ async function getKey(permission: string): Promise { const { results: keys } = await masterClient.getKeys() if (permission === 'Public') { - const key = keys.find((key: any) => - key.description.startsWith('Default Search API') - )?.key + const key = keys.find((key: any) => key.name === 'Default Search API Key') + ?.key return key || '' } if (permission === 'Private') { - const key = keys.find((key: any) => - key.description.startsWith('Default Admin API') - )?.key + const key = keys.find((key: any) => key.name === 'Default Admin API Key') + ?.key return key || '' } return MASTER_KEY @@ -81,36 +75,15 @@ async function getClient(permission: string): Promise { const clearAllIndexes = async (config: Config): Promise => { const client = new MeiliSearch(config) - const response = await client.getRawIndexes() - const indexes = response.map((elem) => elem.uid) + const { results } = await client.getRawIndexes() + const indexes = results.map((elem) => elem.uid) const taskIds = [] for (const indexUid of indexes) { - const { uid } = await client.index(indexUid).delete() - taskIds.push(uid) + const { taskUid } = await client.index(indexUid).delete() + taskIds.push(taskUid) } await client.waitForTasks(taskIds) - - await expect(client.getIndexes()).resolves.toHaveLength(0) -} - -async function waitForDumpProcessing( - dumpId: string, - client: MeiliSearch, - { - timeOutMs = 5000, - intervalMs = 50, - }: { timeOutMs?: number; intervalMs?: number } = {} -): Promise { - const startingTime = Date.now() - while (Date.now() - startingTime < timeOutMs) { - const response = await client.getDumpStatus(dumpId) - if (response.status !== 'in_progress') return response - await sleep(intervalMs) - } - throw new MeiliSearchTimeOutError( - `timeout of ${timeOutMs}ms has exceeded on process ${dumpId} when waiting for the dump creation process to be done.` - ) } function decode64(buff: string) { @@ -200,7 +173,6 @@ export { MASTER_KEY, MeiliSearch, Index, - waitForDumpProcessing, getClient, getKey, decode64, diff --git a/tests/wait_for_task.test.ts b/tests/wait_for_task.test.ts index 730032a33..a19aa2950 100644 --- a/tests/wait_for_task.test.ts +++ b/tests/wait_for_task.test.ts @@ -21,99 +21,149 @@ describe.each([{ permission: 'Master' }, { permission: 'Private' }])( ({ permission }) => { beforeEach(async () => { const client = await getClient('Master') - const { uid } = await client.createIndex(index.uid) - await client.waitForTask(uid) + const { taskUid } = await client.createIndex(index.uid) + await client.waitForTask(taskUid) }) - // Client Wait for tasks + // Client Wait for task test(`${permission} key: Tests wait for task in client until done and resolved`, async () => { const client = await getClient(permission) - const { uid } = await client.index(index.uid).addDocuments(dataset) - const update = await client.waitForTask(uid) + const { taskUid } = await client.index(index.uid).addDocuments(dataset) + + const update = await client.waitForTask(taskUid) + expect(update).toHaveProperty('status', TaskStatus.TASK_SUCCEEDED) }) test(`${permission} key: Tests wait for task in client with custom interval and timeout until done and resolved`, async () => { const client = await getClient(permission) - const { uid } = await client.index(index.uid).addDocuments(dataset) - const update = await client.waitForTask(uid, { + const { taskUid } = await client.index(index.uid).addDocuments(dataset) + + const update = await client.waitForTask(taskUid, { timeOutMs: 6000, intervalMs: 100, }) + expect(update).toHaveProperty('status', TaskStatus.TASK_SUCCEEDED) }) test(`${permission} key: Tests wait for task in client with custom timeout and interval at 0 done and resolved`, async () => { const client = await getClient(permission) - const { uid } = await client.index(index.uid).addDocuments(dataset) - const update = await client.waitForTask(uid, { + const { taskUid } = await client.index(index.uid).addDocuments(dataset) + + const update = await client.waitForTask(taskUid, { timeOutMs: 6000, intervalMs: 0, }) + expect(update).toHaveProperty('status', TaskStatus.TASK_SUCCEEDED) }) test(`${permission} key: Try to wait for task in client with small timeout and raise an error`, async () => { const client = await getClient(permission) - const { uid } = await client.index(index.uid).addDocuments(dataset) + + const { taskUid } = await client.index(index.uid).addDocuments(dataset) + await expect( - client.waitForTask(uid, { timeOutMs: 0 }) + client.waitForTask(taskUid, { timeOutMs: 0 }) ).rejects.toHaveProperty('name', 'MeiliSearchTimeOutError') }) - // Client Wait for tasks + // Index Wait for task + test(`${permission} key: Tests wait for task with an index instance`, async () => { + const client = await getClient(permission) + const { taskUid } = await client.index(index.uid).addDocuments(dataset) + + const update = await client.index(index.uid).waitForTask(taskUid) + + expect(update).toHaveProperty('status', TaskStatus.TASK_SUCCEEDED) + }) + // Client Wait for tasks test(`${permission} key: Tests wait for tasks in client until done and resolved`, async () => { const client = await getClient(permission) - const { uid: task1 } = await client.index(index.uid).addDocuments(dataset) - const { uid: task2 } = await client + const { taskUid: task1 } = await client + .index(index.uid) + .addDocuments(dataset) + const { taskUid: task2 } = await client .index(index.uid) - .updateSettings({ searchableAttributes: [] }) - const update = await client.waitForTasks([task1, task2]) - const [update1, update2] = update.results + .addDocuments(dataset) + + const tasks = await client.waitForTasks([task1, task2]) + const [update1, update2] = tasks + expect(update1).toHaveProperty('status', TaskStatus.TASK_SUCCEEDED) expect(update2).toHaveProperty('status', TaskStatus.TASK_SUCCEEDED) }) test(`${permission} key: Tests wait for tasks in client with custom interval and timeout until done and resolved`, async () => { const client = await getClient(permission) - const { uid: task1 } = await client.index(index.uid).addDocuments(dataset) - const { uid: task2 } = await client + const { taskUid: task1 } = await client .index(index.uid) - .updateSettings({ searchableAttributes: [] }) - const update = await client.waitForTasks([task1, task2], { + .addDocuments(dataset) + const { taskUid: task2 } = await client + .index(index.uid) + .addDocuments(dataset) + + const tasks = await client.waitForTasks([task1, task2], { timeOutMs: 6000, intervalMs: 100, }) - const [update1, update2] = update.results + const [update1, update2] = tasks + expect(update1).toHaveProperty('status', TaskStatus.TASK_SUCCEEDED) expect(update2).toHaveProperty('status', TaskStatus.TASK_SUCCEEDED) }) test(`${permission} key: Tests wait for tasks in client with custom timeout and interval at 0 done and resolved`, async () => { const client = await getClient(permission) - const { uid: task1 } = await client.index(index.uid).addDocuments(dataset) - const { uid: task2 } = await client + const { taskUid: task1 } = await client .index(index.uid) - .updateSettings({ searchableAttributes: [] }) - const update = await client.waitForTasks([task1, task2], { + .addDocuments(dataset) + const { taskUid: task2 } = await client + .index(index.uid) + .addDocuments(dataset) + + const tasks = await client.waitForTasks([task1, task2], { timeOutMs: 6000, intervalMs: 0, }) - const [update1, update2] = update.results + const [update1, update2] = tasks + expect(update1).toHaveProperty('status', TaskStatus.TASK_SUCCEEDED) expect(update2).toHaveProperty('status', TaskStatus.TASK_SUCCEEDED) }) test(`${permission} key: Tests to wait for tasks in client with small timeout and raise an error`, async () => { const client = await getClient(permission) - const { uid: task1 } = await client.index(index.uid).addDocuments(dataset) - const { uid: task2 } = await client + + const { taskUid: task1 } = await client .index(index.uid) - .updateSettings({ searchableAttributes: [] }) + .addDocuments(dataset) + const { taskUid: task2 } = await client + .index(index.uid) + .addDocuments(dataset) + await expect( client.waitForTasks([task1, task2], { timeOutMs: 0 }) ).rejects.toHaveProperty('name', 'MeiliSearchTimeOutError') }) + + // Index Wait for tasks + test(`${permission} key: Tests wait for tasks with indx instance`, async () => { + const client = await getClient(permission) + const { taskUid: task1 } = await client + .index(index.uid) + .addDocuments(dataset) + const { taskUid: task2 } = await client + .index(index.uid) + .addDocuments(dataset) + + const tasks = await client.index(index.uid).waitForTasks([task1, task2]) + const [update1, update2] = tasks + + expect(update1).toHaveProperty('status', TaskStatus.TASK_SUCCEEDED) + expect(update2).toHaveProperty('status', TaskStatus.TASK_SUCCEEDED) + }) } )