diff --git a/src/clients/client.ts b/src/clients/client.ts index 0d21e756a..bb1d7181b 100644 --- a/src/clients/client.ts +++ b/src/clients/client.ts @@ -98,7 +98,7 @@ class Client { * @returns Promise returning array of raw index information */ async getIndexes( - parameters: IndexesQuery = {}, + parameters?: IndexesQuery, ): Promise> { const rawIndexes = await this.getRawIndexes(parameters); const indexes: Index[] = rawIndexes.results.map( @@ -114,11 +114,10 @@ class Client { * @returns Promise returning array of raw index information */ async getRawIndexes( - parameters: IndexesQuery = {}, + parameters?: IndexesQuery, ): Promise> { - const url = `indexes`; return >( - await this.httpRequest.get({ relativeURL: url, params: parameters }) + await this.httpRequest.get({ relativeURL: "indexes", params: parameters }) ); } @@ -131,7 +130,7 @@ class Client { */ async createIndex( uid: string, - options: IndexOptions = {}, + options?: IndexOptions, ): Promise { return await Index.create(uid, options, this.config); } @@ -145,7 +144,7 @@ class Client { */ async updateIndex( uid: string, - options: IndexOptions = {}, + options?: IndexOptions, ): Promise { return await new Index(this.config, uid).update(options); } @@ -231,10 +230,11 @@ class Client { queries: MultiSearchParams | FederatedMultiSearchParams, config?: Partial, ): Promise | SearchResponse> { - const url = `multi-search`; - return | SearchResponse>( - await this.httpRequest.post({ relativeURL: url, body: queries }) + await this.httpRequest.post({ + relativeURL: "multi-search", + body: queries, + }) ); } @@ -248,7 +248,7 @@ class Client { * @param parameters - Parameters to browse the tasks * @returns Promise returning all tasks */ - async getTasks(parameters: TasksQuery = {}): Promise { + async getTasks(parameters?: TasksQuery): Promise { return await this.tasks.getTasks(parameters); } @@ -312,7 +312,7 @@ class Client { * @param parameters - Parameters to filter the tasks. * @returns Promise containing an EnqueuedTask */ - async deleteTasks(parameters: DeleteTasksQuery = {}): Promise { + async deleteTasks(parameters?: DeleteTasksQuery): Promise { return await this.tasks.deleteTasks(parameters); } @@ -326,10 +326,9 @@ class Client { * @param parameters - Parameters to browse the indexes * @returns Promise returning an object with keys */ - async getKeys(parameters: KeysQuery = {}): Promise { - const url = `keys`; + async getKeys(parameters?: KeysQuery): Promise { const keys = ( - await this.httpRequest.get({ relativeURL: url, params: parameters }) + await this.httpRequest.get({ relativeURL: "keys", params: parameters }) ); keys.results = keys.results.map((key) => ({ @@ -348,8 +347,7 @@ class Client { * @returns Promise returning a key */ async getKey(keyOrUid: string): Promise { - const url = `keys/${keyOrUid}`; - return await this.httpRequest.get({ relativeURL: url }); + return await this.httpRequest.get({ relativeURL: `keys/${keyOrUid}` }); } /** @@ -359,9 +357,8 @@ class Client { * @returns Promise returning a key */ async createKey(options: KeyCreation): Promise { - const url = `keys`; return ( - await this.httpRequest.post({ relativeURL: url, body: options }) + await this.httpRequest.post({ relativeURL: "keys", body: options }) ); } @@ -373,10 +370,10 @@ class Client { * @returns Promise returning a key */ async updateKey(keyOrUid: string, options: KeyUpdate): Promise { - const url = `keys/${keyOrUid}`; - return ( - await this.httpRequest.patch({ relativeURL: url, body: options }) - ); + return await this.httpRequest.patch({ + relativeURL: `keys/${keyOrUid}`, + body: options, + }); } /** @@ -386,8 +383,7 @@ class Client { * @returns */ async deleteKey(keyOrUid: string): Promise { - const url = `keys/${keyOrUid}`; - await this.httpRequest.delete({ relativeURL: url }); + await this.httpRequest.delete({ relativeURL: `keys/${keyOrUid}` }); } /// @@ -400,8 +396,7 @@ class Client { * @returns Promise returning an object with health details */ async health(): Promise { - const url = `health`; - return await this.httpRequest.get({ relativeURL: url }); + return await this.httpRequest.get({ relativeURL: "health" }); } /** @@ -428,8 +423,7 @@ class Client { * @returns Promise returning object of all the stats */ async getStats(): Promise { - const url = `stats`; - return await this.httpRequest.get({ relativeURL: url }); + return await this.httpRequest.get({ relativeURL: "stats" }); } /// @@ -442,8 +436,7 @@ class Client { * @returns Promise returning object with version details */ async getVersion(): Promise { - const url = `version`; - return await this.httpRequest.get({ relativeURL: url }); + return await this.httpRequest.get({ relativeURL: "version" }); } /// @@ -456,9 +449,8 @@ class Client { * @returns Promise returning object of the enqueued task */ async createDump(): Promise { - const url = `dumps`; const task = ( - await this.httpRequest.post({ relativeURL: url }) + await this.httpRequest.post({ relativeURL: "dumps" }) ); return new EnqueuedTask(task); } @@ -473,9 +465,8 @@ class Client { * @returns Promise returning object of the enqueued task */ async createSnapshot(): Promise { - const url = `snapshots`; const task = ( - await this.httpRequest.post({ relativeURL: url }) + await this.httpRequest.post({ relativeURL: "snapshots" }) ); return new EnqueuedTask(task); diff --git a/src/http-requests.ts b/src/http-requests.ts index fcd099090..0c4ef5254 100644 --- a/src/http-requests.ts +++ b/src/http-requests.ts @@ -7,7 +7,7 @@ import { MeiliSearchRequestError, } from "./errors"; -import { addTrailingSlash, addProtocolIfNotPresent } from "./utils"; +import { addProtocolIfNotPresent, addTrailingSlash } from "./utils"; type URLSearchParamsRecord = Record< string, @@ -74,12 +74,6 @@ function getHeaders(config: Config, headersInit?: HeadersInit): Headers { return headers; } -function constructHostURL(host: string): string { - host = addProtocolIfNotPresent(host); - host = addTrailingSlash(host); - return host; -} - type RequestOptions = { relativeURL: string; method?: string; @@ -91,50 +85,50 @@ type RequestOptions = { export type MethodOptions = Omit; export class HttpRequests { - url: URL; - requestInit: Omit, "headers"> & { + #url: URL; + #requestInit: Omit, "headers"> & { headers: Headers; }; - httpClient: Config["httpClient"]; - requestTimeout?: number; + #requestFn: NonNullable; + #isCustomRequestFnProvided: boolean; + #requestTimeout?: number; constructor(config: Config) { - const host = constructHostURL(config.host); + const host = addTrailingSlash(addProtocolIfNotPresent(config.host)); try { - this.url = new URL(host); + this.#url = new URL(host); } catch (error) { throw new MeiliSearchError("The provided host is not valid", { cause: error, }); } - this.requestInit = { + this.#requestInit = { ...config.requestInit, headers: getHeaders(config, config.requestInit?.headers), }; - this.httpClient = config.httpClient; - this.requestTimeout = config.timeout; + this.#requestFn = config.httpClient ?? fetch; + this.#isCustomRequestFnProvided = config.httpClient !== undefined; + this.#requestTimeout = config.timeout; } async #fetchWithTimeout( ...fetchParams: Parameters ): Promise { return new Promise((resolve, reject) => { - const fetchFn = this.httpClient ? this.httpClient : fetch; - - const fetchPromise = fetchFn(...fetchParams); + const fetchPromise = this.#requestFn(...fetchParams); const promises: Array> = [fetchPromise]; // TimeoutPromise will not run if undefined or zero let timeoutId: ReturnType; - if (this.requestTimeout) { + if (this.#requestTimeout) { const timeoutPromise = new Promise((_, reject) => { timeoutId = setTimeout(() => { reject(new Error("Error: Request Timed Out")); - }, this.requestTimeout); + }, this.#requestTimeout); }); promises.push(timeoutPromise); @@ -156,7 +150,7 @@ export class HttpRequests { headers, body, }: RequestOptions): Promise { - const url = new URL(relativeURL, this.url); + const url = new URL(relativeURL, this.#url); if (params !== undefined) { appendRecordToURLSearchParams(url.searchParams, params); } @@ -168,7 +162,7 @@ export class HttpRequests { isCustomContentTypeProvided = headers.has("Content-Type"); - for (const [key, val] of this.requestInit.headers.entries()) { + for (const [key, val] of this.#requestInit.headers.entries()) { if (!headers.has(key)) { headers.set(key, val); } @@ -185,8 +179,8 @@ export class HttpRequests { ? // this will throw an error for any value that is not serializable JSON.stringify(body) : body, - ...this.requestInit, - headers: headers ?? this.requestInit.headers, + ...this.#requestInit, + headers: headers ?? this.#requestInit.headers, }); const response = await responsePromise.catch((error: unknown) => { @@ -194,7 +188,7 @@ export class HttpRequests { }); // When using a custom HTTP client, the response is returned to allow the user to parse/handle it as they see fit - if (this.httpClient !== undefined) { + if (this.#isCustomRequestFnProvided) { return response; } diff --git a/src/indexes.ts b/src/indexes.ts index 1034a24cc..baed2163b 100644 --- a/src/indexes.ts +++ b/src/indexes.ts @@ -58,7 +58,6 @@ import { UpdateDocumentsByFunctionOptions, EnqueuedTaskObject, } from "./types"; -import { removeUndefinedFromObject } from "./utils"; import { HttpRequests } from "./http-requests"; import { Task, TaskClient } from "./task"; import { EnqueuedTask } from "./enqueued-task"; @@ -103,10 +102,8 @@ class Index = Record> { options?: S, config?: Partial, ): Promise> { - const url = `indexes/${this.uid}/search`; - return >await this.httpRequest.post({ - relativeURL: url, + relativeURL: `indexes/${this.uid}/search`, body: { q: query, ...options }, }); } @@ -127,8 +124,6 @@ class Index = Record> { options?: S, config?: Partial, ): Promise> { - const url = `indexes/${this.uid}/search`; - // @TODO: Make this a type thing instead of a runtime thing const parseFilter = (filter?: Filter): string | undefined => { if (typeof filter === "string") return filter; @@ -153,7 +148,7 @@ class Index = Record> { }; return >await this.httpRequest.get({ - relativeURL: url, + relativeURL: `indexes/${this.uid}/search`, params: getParams, }); } @@ -169,11 +164,10 @@ class Index = Record> { params: SearchForFacetValuesParams, config?: Partial, ): Promise { - const url = `indexes/${this.uid}/facet-search`; - - return ( - await this.httpRequest.post({ relativeURL: url, body: params }) - ); + return await this.httpRequest.post({ + relativeURL: `indexes/${this.uid}/facet-search`, + body: params, + }); } /** @@ -186,11 +180,10 @@ class Index = Record> { D extends Record = T, S extends SearchParams = SearchParams, >(params: SearchSimilarDocumentsParams): Promise> { - const url = `indexes/${this.uid}/similar`; - - return >( - await this.httpRequest.post({ relativeURL: url, body: params }) - ); + return >await this.httpRequest.post({ + relativeURL: `indexes/${this.uid}/similar`, + body: params, + }); } /// @@ -203,8 +196,9 @@ class Index = Record> { * @returns Promise containing index information */ async getRawInfo(): Promise { - const url = `indexes/${this.uid}`; - const res = await this.httpRequest.get({ relativeURL: url }); + const res = ( + await this.httpRequest.get({ relativeURL: `indexes/${this.uid}` }) + ); this.primaryKey = res.primaryKey; this.updatedAt = new Date(res.updatedAt); this.createdAt = new Date(res.createdAt); @@ -244,10 +238,9 @@ class Index = Record> { options: IndexOptions = {}, config: Config, ): Promise { - const url = `indexes`; const req = new HttpRequests(config); const task = ( - await req.post({ relativeURL: url, body: { ...options, uid } }) + await req.post({ relativeURL: `indexes`, body: { ...options, uid } }) ); return new EnqueuedTask(task); @@ -260,15 +253,12 @@ class Index = Record> { * @returns Promise to the current Index object with updated information */ async update(data: IndexOptions): Promise { - const url = `indexes/${this.uid}`; - // @TODO: Something is not right - const task = ( - await this.httpRequest.patch({ relativeURL: url, body: data }) - ); - - task.enqueuedAt = new Date(task.enqueuedAt); + const task = await this.httpRequest.patch({ + relativeURL: `indexes/${this.uid}`, + body: data, + }); - return task; + return new EnqueuedTask(task); } /** @@ -277,9 +267,8 @@ class Index = Record> { * @returns Promise which resolves when index is deleted successfully */ async delete(): Promise { - const url = `indexes/${this.uid}`; const task = ( - await this.httpRequest.delete({ relativeURL: url }) + await this.httpRequest.delete({ relativeURL: `indexes/${this.uid}` }) ); return new EnqueuedTask(task); @@ -295,7 +284,7 @@ class Index = Record> { * @param parameters - Parameters to browse the tasks * @returns Promise containing all tasks */ - async getTasks(parameters: TasksQuery = {}): Promise { + async getTasks(parameters?: TasksQuery): Promise { return await this.tasks.getTasks({ ...parameters, indexUids: [this.uid] }); } @@ -353,8 +342,9 @@ class Index = Record> { * @returns Promise containing object with stats of the index */ async getStats(): Promise { - const url = `indexes/${this.uid}/stats`; - return await this.httpRequest.get({ relativeURL: url }); + return ( + await this.httpRequest.get({ relativeURL: `indexes/${this.uid}/stats` }) + ); } /// @@ -369,18 +359,17 @@ class Index = Record> { * @returns Promise containing the returned documents */ async getDocuments = T>( - parameters: DocumentsQuery = {}, + parameters?: DocumentsQuery, ): Promise> { - parameters = removeUndefinedFromObject(parameters); + const relativeBaseURL = `indexes/${this.uid}/documents`; // In case `filter` is provided, use `POST /documents/fetch` - if (parameters.filter !== undefined) { + if (parameters?.filter !== undefined) { try { - const url = `indexes/${this.uid}/documents/fetch`; - - return >( - await this.httpRequest.post({ relativeURL: url, body: parameters }) - ); + return >await this.httpRequest.post({ + relativeURL: `${relativeBaseURL}/fetch`, + body: parameters, + }); } catch (e) { if (e instanceof MeiliSearchRequestError) { e.message = versionErrorHintMessage(e.message, "getDocuments"); @@ -392,9 +381,8 @@ class Index = Record> { } } else { // Else use `GET /documents` method - const url = `indexes/${this.uid}/documents`; return >await this.httpRequest.get({ - relativeURL: url, + relativeURL: relativeBaseURL, params: { ...parameters, // Transform fields to query parameter string format @@ -417,8 +405,6 @@ class Index = Record> { documentId: string | number, parameters?: DocumentQuery, ): Promise { - const url = `indexes/${this.uid}/documents/${documentId}`; - const fields = (() => { if (Array.isArray(parameters?.fields)) { return parameters?.fields?.join(","); @@ -427,7 +413,7 @@ class Index = Record> { })(); return await this.httpRequest.get({ - relativeURL: url, + relativeURL: `indexes/${this.uid}/documents/${documentId}`, params: { ...parameters, fields, @@ -446,9 +432,8 @@ class Index = Record> { documents: T[], options?: DocumentOptions, ): Promise { - const url = `indexes/${this.uid}/documents`; const task = await this.httpRequest.post({ - relativeURL: url, + relativeURL: `indexes/${this.uid}/documents`, params: options, body: documents, }); @@ -471,10 +456,8 @@ class Index = Record> { contentType: ContentType, queryParams?: RawDocumentAdditionOptions, ): Promise { - const url = `indexes/${this.uid}/documents`; - const task = await this.httpRequest.post({ - relativeURL: url, + relativeURL: `indexes/${this.uid}/documents`, body: documents, params: queryParams, headers: { "Content-Type": contentType }, @@ -516,9 +499,8 @@ class Index = Record> { documents: Array>, options?: DocumentOptions, ): Promise { - const url = `indexes/${this.uid}/documents`; const task = await this.httpRequest.put({ - relativeURL: url, + relativeURL: `indexes/${this.uid}/documents`, params: options, body: documents, }); @@ -563,10 +545,8 @@ class Index = Record> { contentType: ContentType, queryParams?: RawDocumentAdditionOptions, ): Promise { - const url = `indexes/${this.uid}/documents`; - const task = await this.httpRequest.put({ - relativeURL: url, + relativeURL: `indexes/${this.uid}/documents`, body: documents, params: queryParams, headers: { "Content-Type": contentType }, @@ -582,10 +562,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async deleteDocument(documentId: string | number): Promise { - const url = `indexes/${this.uid}/documents/${documentId}`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/documents/${documentId}`, + }); return new EnqueuedTask(task); } @@ -610,11 +589,10 @@ class Index = Record> { const endpoint = isDocumentsDeletionQuery ? "documents/delete" : "documents/delete-batch"; - const url = `indexes/${this.uid}/${endpoint}`; try { const task = await this.httpRequest.post({ - relativeURL: url, + relativeURL: `indexes/${this.uid}/${endpoint}`, body: params, }); @@ -636,10 +614,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async deleteAllDocuments(): Promise { - const url = `indexes/${this.uid}/documents`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/documents`, + }); return new EnqueuedTask(task); } @@ -659,9 +636,8 @@ class Index = Record> { async updateDocumentsByFunction( options: UpdateDocumentsByFunctionOptions, ): Promise { - const url = `indexes/${this.uid}/documents/edit`; const task = await this.httpRequest.post({ - relativeURL: url, + relativeURL: `indexes/${this.uid}/documents/edit`, body: options, }); @@ -678,8 +654,9 @@ class Index = Record> { * @returns Promise containing Settings object */ async getSettings(): Promise { - const url = `indexes/${this.uid}/settings`; - return await this.httpRequest.get({ relativeURL: url }); + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings`, + }); } /** @@ -689,10 +666,10 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async updateSettings(settings: Settings): Promise { - const url = `indexes/${this.uid}/settings`; - const task = ( - await this.httpRequest.patch({ relativeURL: url, body: settings }) - ); + const task = await this.httpRequest.patch({ + relativeURL: `indexes/${this.uid}/settings`, + body: settings, + }); return new EnqueuedTask(task); } @@ -703,10 +680,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetSettings(): Promise { - const url = `indexes/${this.uid}/settings`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings`, + }); return new EnqueuedTask(task); } @@ -721,9 +697,9 @@ class Index = Record> { * @returns Promise containing object of pagination settings */ async getPagination(): Promise { - const url = `indexes/${this.uid}/settings/pagination`; - // @TODO: I don't like this type - return await this.httpRequest.get({ relativeURL: url }); + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/pagination`, + }); } /** @@ -735,10 +711,10 @@ class Index = Record> { async updatePagination( pagination: PaginationSettings, ): Promise { - const url = `indexes/${this.uid}/settings/pagination`; - const task = ( - await this.httpRequest.patch({ relativeURL: url, body: pagination }) - ); + const task = await this.httpRequest.patch({ + relativeURL: `indexes/${this.uid}/settings/pagination`, + body: pagination, + }); return new EnqueuedTask(task); } @@ -749,10 +725,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetPagination(): Promise { - const url = `indexes/${this.uid}/settings/pagination`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/pagination`, + }); return new EnqueuedTask(task); } @@ -764,12 +739,12 @@ class Index = Record> { /** * Get the list of all synonyms * - * @returns Promise containing object of synonym mappings + * @returns Promise containing record of synonym mappings */ - async getSynonyms(): Promise { - const url = `indexes/${this.uid}/settings/synonyms`; - // @TODO: I don't like this type - return await this.httpRequest.get({ relativeURL: url }); + async getSynonyms(): Promise { + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/synonyms`, + }); } /** @@ -779,10 +754,10 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async updateSynonyms(synonyms: Synonyms): Promise { - const url = `indexes/${this.uid}/settings/synonyms`; - const task = ( - await this.httpRequest.put({ relativeURL: url, body: synonyms }) - ); + const task = await this.httpRequest.put({ + relativeURL: `indexes/${this.uid}/settings/synonyms`, + body: synonyms, + }); return new EnqueuedTask(task); } @@ -793,10 +768,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetSynonyms(): Promise { - const url = `indexes/${this.uid}/settings/synonyms`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/synonyms`, + }); return new EnqueuedTask(task); } @@ -810,9 +784,10 @@ class Index = Record> { * * @returns Promise containing array of stop-words */ - async getStopWords(): Promise { - const url = `indexes/${this.uid}/settings/stop-words`; - return await this.httpRequest.get({ relativeURL: url }); + async getStopWords(): Promise { + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/stop-words`, + }); } /** @@ -822,10 +797,10 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async updateStopWords(stopWords: StopWords): Promise { - const url = `indexes/${this.uid}/settings/stop-words`; - const task = ( - await this.httpRequest.put({ relativeURL: url, body: stopWords }) - ); + const task = await this.httpRequest.put({ + relativeURL: `indexes/${this.uid}/settings/stop-words`, + body: stopWords, + }); return new EnqueuedTask(task); } @@ -836,10 +811,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetStopWords(): Promise { - const url = `indexes/${this.uid}/settings/stop-words`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/stop-words`, + }); return new EnqueuedTask(task); } @@ -853,9 +827,10 @@ class Index = Record> { * * @returns Promise containing array of ranking-rules */ - async getRankingRules(): Promise { - const url = `indexes/${this.uid}/settings/ranking-rules`; - return await this.httpRequest.get({ relativeURL: url }); + async getRankingRules(): Promise { + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/ranking-rules`, + }); } /** @@ -866,10 +841,10 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async updateRankingRules(rankingRules: RankingRules): Promise { - const url = `indexes/${this.uid}/settings/ranking-rules`; - const task = ( - await this.httpRequest.put({ relativeURL: url, body: rankingRules }) - ); + const task = await this.httpRequest.put({ + relativeURL: `indexes/${this.uid}/settings/ranking-rules`, + body: rankingRules, + }); return new EnqueuedTask(task); } @@ -880,10 +855,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetRankingRules(): Promise { - const url = `indexes/${this.uid}/settings/ranking-rules`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/ranking-rules`, + }); return new EnqueuedTask(task); } @@ -897,9 +871,10 @@ class Index = Record> { * * @returns Promise containing the distinct-attribute of the index */ - async getDistinctAttribute(): Promise { - const url = `indexes/${this.uid}/settings/distinct-attribute`; - return await this.httpRequest.get({ relativeURL: url }); + async getDistinctAttribute(): Promise { + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/distinct-attribute`, + }); } /** @@ -911,10 +886,10 @@ class Index = Record> { async updateDistinctAttribute( distinctAttribute: DistinctAttribute, ): Promise { - const url = `indexes/${this.uid}/settings/distinct-attribute`; - const task = ( - await this.httpRequest.put({ relativeURL: url, body: distinctAttribute }) - ); + const task = await this.httpRequest.put({ + relativeURL: `indexes/${this.uid}/settings/distinct-attribute`, + body: distinctAttribute, + }); return new EnqueuedTask(task); } @@ -925,10 +900,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetDistinctAttribute(): Promise { - const url = `indexes/${this.uid}/settings/distinct-attribute`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/distinct-attribute`, + }); return new EnqueuedTask(task); } @@ -942,9 +916,10 @@ class Index = Record> { * * @returns Promise containing an array of filterable-attributes */ - async getFilterableAttributes(): Promise { - const url = `indexes/${this.uid}/settings/filterable-attributes`; - return await this.httpRequest.get({ relativeURL: url }); + async getFilterableAttributes(): Promise { + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/filterable-attributes`, + }); } /** @@ -957,9 +932,8 @@ class Index = Record> { async updateFilterableAttributes( filterableAttributes: FilterableAttributes, ): Promise { - const url = `indexes/${this.uid}/settings/filterable-attributes`; const task = await this.httpRequest.put({ - relativeURL: url, + relativeURL: `indexes/${this.uid}/settings/filterable-attributes`, body: filterableAttributes, }); @@ -972,10 +946,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetFilterableAttributes(): Promise { - const url = `indexes/${this.uid}/settings/filterable-attributes`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/filterable-attributes`, + }); return new EnqueuedTask(task); } @@ -989,9 +962,10 @@ class Index = Record> { * * @returns Promise containing array of sortable-attributes */ - async getSortableAttributes(): Promise { - const url = `indexes/${this.uid}/settings/sortable-attributes`; - return await this.httpRequest.get({ relativeURL: url }); + async getSortableAttributes(): Promise { + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/sortable-attributes`, + }); } /** @@ -1004,10 +978,10 @@ class Index = Record> { async updateSortableAttributes( sortableAttributes: SortableAttributes, ): Promise { - const url = `indexes/${this.uid}/settings/sortable-attributes`; - const task = ( - await this.httpRequest.put({ relativeURL: url, body: sortableAttributes }) - ); + const task = await this.httpRequest.put({ + relativeURL: `indexes/${this.uid}/settings/sortable-attributes`, + body: sortableAttributes, + }); return new EnqueuedTask(task); } @@ -1018,10 +992,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetSortableAttributes(): Promise { - const url = `indexes/${this.uid}/settings/sortable-attributes`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/sortable-attributes`, + }); return new EnqueuedTask(task); } @@ -1035,9 +1008,10 @@ class Index = Record> { * * @returns Promise containing array of searchable-attributes */ - async getSearchableAttributes(): Promise { - const url = `indexes/${this.uid}/settings/searchable-attributes`; - return await this.httpRequest.get({ relativeURL: url }); + async getSearchableAttributes(): Promise { + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/searchable-attributes`, + }); } /** @@ -1050,9 +1024,8 @@ class Index = Record> { async updateSearchableAttributes( searchableAttributes: SearchableAttributes, ): Promise { - const url = `indexes/${this.uid}/settings/searchable-attributes`; const task = await this.httpRequest.put({ - relativeURL: url, + relativeURL: `indexes/${this.uid}/settings/searchable-attributes`, body: searchableAttributes, }); @@ -1065,10 +1038,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetSearchableAttributes(): Promise { - const url = `indexes/${this.uid}/settings/searchable-attributes`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/searchable-attributes`, + }); return new EnqueuedTask(task); } @@ -1082,9 +1054,10 @@ class Index = Record> { * * @returns Promise containing array of displayed-attributes */ - async getDisplayedAttributes(): Promise { - const url = `indexes/${this.uid}/settings/displayed-attributes`; - return await this.httpRequest.get({ relativeURL: url }); + async getDisplayedAttributes(): Promise { + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/displayed-attributes`, + }); } /** @@ -1097,9 +1070,8 @@ class Index = Record> { async updateDisplayedAttributes( displayedAttributes: DisplayedAttributes, ): Promise { - const url = `indexes/${this.uid}/settings/displayed-attributes`; const task = await this.httpRequest.put({ - relativeURL: url, + relativeURL: `indexes/${this.uid}/settings/displayed-attributes`, body: displayedAttributes, }); @@ -1112,10 +1084,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetDisplayedAttributes(): Promise { - const url = `indexes/${this.uid}/settings/displayed-attributes`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/displayed-attributes`, + }); return new EnqueuedTask(task); } @@ -1130,8 +1101,9 @@ class Index = Record> { * @returns Promise containing the typo tolerance settings. */ async getTypoTolerance(): Promise { - const url = `indexes/${this.uid}/settings/typo-tolerance`; - return await this.httpRequest.get({ relativeURL: url }); + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/typo-tolerance`, + }); } /** @@ -1144,10 +1116,10 @@ class Index = Record> { async updateTypoTolerance( typoTolerance: TypoTolerance, ): Promise { - const url = `indexes/${this.uid}/settings/typo-tolerance`; - const task = ( - await this.httpRequest.patch({ relativeURL: url, body: typoTolerance }) - ); + const task = await this.httpRequest.patch({ + relativeURL: `indexes/${this.uid}/settings/typo-tolerance`, + body: typoTolerance, + }); return new EnqueuedTask(task); } @@ -1158,10 +1130,9 @@ class Index = Record> { * @returns Promise containing object of the enqueued update */ async resetTypoTolerance(): Promise { - const url = `indexes/${this.uid}/settings/typo-tolerance`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/typo-tolerance`, + }); return new EnqueuedTask(task); } @@ -1176,8 +1147,9 @@ class Index = Record> { * @returns Promise containing object of faceting index settings */ async getFaceting(): Promise { - const url = `indexes/${this.uid}/settings/faceting`; - return await this.httpRequest.get({ relativeURL: url }); + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/faceting`, + }); } /** @@ -1187,10 +1159,10 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async updateFaceting(faceting: Faceting): Promise { - const url = `indexes/${this.uid}/settings/faceting`; - const task = ( - await this.httpRequest.patch({ relativeURL: url, body: faceting }) - ); + const task = await this.httpRequest.patch({ + relativeURL: `indexes/${this.uid}/settings/faceting`, + body: faceting, + }); return new EnqueuedTask(task); } @@ -1201,10 +1173,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetFaceting(): Promise { - const url = `indexes/${this.uid}/settings/faceting`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/faceting`, + }); return new EnqueuedTask(task); } @@ -1218,9 +1189,10 @@ class Index = Record> { * * @returns Promise containing array of separator tokens */ - async getSeparatorTokens(): Promise { - const url = `indexes/${this.uid}/settings/separator-tokens`; - return await this.httpRequest.get({ relativeURL: url }); + async getSeparatorTokens(): Promise { + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/separator-tokens`, + }); } /** @@ -1232,10 +1204,10 @@ class Index = Record> { async updateSeparatorTokens( separatorTokens: SeparatorTokens, ): Promise { - const url = `indexes/${this.uid}/settings/separator-tokens`; - const task = ( - await this.httpRequest.put({ relativeURL: url, body: separatorTokens }) - ); + const task = await this.httpRequest.put({ + relativeURL: `indexes/${this.uid}/settings/separator-tokens`, + body: separatorTokens, + }); return new EnqueuedTask(task); } @@ -1246,10 +1218,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetSeparatorTokens(): Promise { - const url = `indexes/${this.uid}/settings/separator-tokens`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/separator-tokens`, + }); return new EnqueuedTask(task); } @@ -1263,9 +1234,10 @@ class Index = Record> { * * @returns Promise containing array of non-separator tokens */ - async getNonSeparatorTokens(): Promise { - const url = `indexes/${this.uid}/settings/non-separator-tokens`; - return await this.httpRequest.get({ relativeURL: url }); + async getNonSeparatorTokens(): Promise { + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/non-separator-tokens`, + }); } /** @@ -1277,10 +1249,10 @@ class Index = Record> { async updateNonSeparatorTokens( nonSeparatorTokens: NonSeparatorTokens, ): Promise { - const url = `indexes/${this.uid}/settings/non-separator-tokens`; - const task = ( - await this.httpRequest.put({ relativeURL: url, body: nonSeparatorTokens }) - ); + const task = await this.httpRequest.put({ + relativeURL: `indexes/${this.uid}/settings/non-separator-tokens`, + body: nonSeparatorTokens, + }); return new EnqueuedTask(task); } @@ -1291,10 +1263,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetNonSeparatorTokens(): Promise { - const url = `indexes/${this.uid}/settings/non-separator-tokens`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/non-separator-tokens`, + }); return new EnqueuedTask(task); } @@ -1308,9 +1279,10 @@ class Index = Record> { * * @returns Promise containing the dictionary settings */ - async getDictionary(): Promise { - const url = `indexes/${this.uid}/settings/dictionary`; - return await this.httpRequest.get({ relativeURL: url }); + async getDictionary(): Promise { + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/dictionary`, + }); } /** @@ -1320,9 +1292,8 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask or null */ async updateDictionary(dictionary: Dictionary): Promise { - const url = `indexes/${this.uid}/settings/dictionary`; const task = await this.httpRequest.put({ - relativeURL: url, + relativeURL: `indexes/${this.uid}/settings/dictionary`, body: dictionary, }); @@ -1335,10 +1306,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetDictionary(): Promise { - const url = `indexes/${this.uid}/settings/dictionary`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/dictionary`, + }); return new EnqueuedTask(task); } @@ -1353,8 +1323,9 @@ class Index = Record> { * @returns Promise containing the proximity precision settings */ async getProximityPrecision(): Promise { - const url = `indexes/${this.uid}/settings/proximity-precision`; - return await this.httpRequest.get({ relativeURL: url }); + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/proximity-precision`, + }); } /** @@ -1367,10 +1338,10 @@ class Index = Record> { async updateProximityPrecision( proximityPrecision: ProximityPrecision, ): Promise { - const url = `indexes/${this.uid}/settings/proximity-precision`; - const task = ( - await this.httpRequest.put({ relativeURL: url, body: proximityPrecision }) - ); + const task = await this.httpRequest.put({ + relativeURL: `indexes/${this.uid}/settings/proximity-precision`, + body: proximityPrecision, + }); return new EnqueuedTask(task); } @@ -1381,10 +1352,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetProximityPrecision(): Promise { - const url = `indexes/${this.uid}/settings/proximity-precision`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/proximity-precision`, + }); return new EnqueuedTask(task); } @@ -1399,8 +1369,9 @@ class Index = Record> { * @returns Promise containing the embedders settings */ async getEmbedders(): Promise { - const url = `indexes/${this.uid}/settings/embedders`; - return await this.httpRequest.get({ relativeURL: url }); + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/embedders`, + }); } /** @@ -1410,10 +1381,10 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask or null */ async updateEmbedders(embedders: Embedders): Promise { - const url = `indexes/${this.uid}/settings/embedders`; - const task = ( - await this.httpRequest.patch({ relativeURL: url, body: embedders }) - ); + const task = await this.httpRequest.patch({ + relativeURL: `indexes/${this.uid}/settings/embedders`, + body: embedders, + }); return new EnqueuedTask(task); } @@ -1424,10 +1395,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetEmbedders(): Promise { - const url = `indexes/${this.uid}/settings/embedders`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/embedders`, + }); return new EnqueuedTask(task); } @@ -1442,8 +1412,9 @@ class Index = Record> { * @returns Promise containing object of SearchCutoffMs settings */ async getSearchCutoffMs(): Promise { - const url = `indexes/${this.uid}/settings/search-cutoff-ms`; - return await this.httpRequest.get({ relativeURL: url }); + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/search-cutoff-ms`, + }); } /** @@ -1455,9 +1426,8 @@ class Index = Record> { async updateSearchCutoffMs( searchCutoffMs: SearchCutoffMs, ): Promise { - const url = `indexes/${this.uid}/settings/search-cutoff-ms`; const task = await this.httpRequest.put({ - relativeURL: url, + relativeURL: `indexes/${this.uid}/settings/search-cutoff-ms`, body: searchCutoffMs, }); @@ -1470,10 +1440,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetSearchCutoffMs(): Promise { - const url = `indexes/${this.uid}/settings/search-cutoff-ms`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/search-cutoff-ms`, + }); return new EnqueuedTask(task); } @@ -1488,10 +1457,9 @@ class Index = Record> { * @returns Promise containing object of localized attributes settings */ async getLocalizedAttributes(): Promise { - const url = `indexes/${this.uid}/settings/localized-attributes`; - return ( - await this.httpRequest.get({ relativeURL: url }) - ); + return await this.httpRequest.get({ + relativeURL: `indexes/${this.uid}/settings/localized-attributes`, + }); } /** @@ -1503,9 +1471,8 @@ class Index = Record> { async updateLocalizedAttributes( localizedAttributes: LocalizedAttributes, ): Promise { - const url = `indexes/${this.uid}/settings/localized-attributes`; const task = await this.httpRequest.put({ - relativeURL: url, + relativeURL: `indexes/${this.uid}/settings/localized-attributes`, body: localizedAttributes, }); @@ -1518,10 +1485,9 @@ class Index = Record> { * @returns Promise containing an EnqueuedTask */ async resetLocalizedAttributes(): Promise { - const url = `indexes/${this.uid}/settings/localized-attributes`; - const task = ( - await this.httpRequest.delete({ relativeURL: url }) - ); + const task = await this.httpRequest.delete({ + relativeURL: `indexes/${this.uid}/settings/localized-attributes`, + }); return new EnqueuedTask(task); } diff --git a/src/task.ts b/src/task.ts index 38ecd2b2d..2577d2ca1 100644 --- a/src/task.ts +++ b/src/task.ts @@ -58,9 +58,8 @@ class TaskClient { * @returns */ async getTask(uid: number): Promise { - const url = `tasks/${uid}`; const taskItem = ( - await this.httpRequest.get({ relativeURL: url }) + await this.httpRequest.get({ relativeURL: `tasks/${uid}` }) ); return new Task(taskItem); } @@ -71,11 +70,9 @@ class TaskClient { * @param params - Parameters to browse the tasks * @returns Promise containing all tasks */ - async getTasks(params: TasksQuery = {}): Promise { - const url = `tasks`; - + async getTasks(params?: TasksQuery): Promise { const tasks = ( - await this.httpRequest.get({ relativeURL: url, params }) + await this.httpRequest.get({ relativeURL: `tasks`, params }) ); return { @@ -142,11 +139,9 @@ class TaskClient { * @param params - Parameters to filter the tasks. * @returns Promise containing an EnqueuedTask */ - async cancelTasks(params: CancelTasksQuery = {}): Promise { - const url = `tasks/cancel`; - + async cancelTasks(params?: CancelTasksQuery): Promise { const task = ( - await this.httpRequest.post({ relativeURL: url, params }) + await this.httpRequest.post({ relativeURL: `tasks/cancel`, params }) ); return new EnqueuedTask(task); @@ -158,11 +153,9 @@ class TaskClient { * @param params - Parameters to filter the tasks. * @returns Promise containing an EnqueuedTask */ - async deleteTasks(params: DeleteTasksQuery = {}): Promise { - const url = `tasks`; - + async deleteTasks(params?: DeleteTasksQuery): Promise { const task = ( - await this.httpRequest.delete({ relativeURL: url, params }) + await this.httpRequest.delete({ relativeURL: `tasks`, params }) ); return new EnqueuedTask(task); } diff --git a/src/types/types.ts b/src/types/types.ts index dcd7b3d99..3ca3735be 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -359,9 +359,7 @@ export type SortableAttributes = string[] | null; export type DisplayedAttributes = string[] | null; export type RankingRules = string[] | null; export type StopWords = string[] | null; -export type Synonyms = { - [field: string]: string[]; -} | null; +export type Synonyms = Record | null; export type TypoTolerance = { enabled?: boolean | null; disableOnAttributes?: string[] | null; @@ -524,9 +522,9 @@ export type TasksQuery = { from?: number; }; -export type CancelTasksQuery = Omit & {}; +export type CancelTasksQuery = Omit; -export type DeleteTasksQuery = Omit & {}; +export type DeleteTasksQuery = Omit; export type EnqueuedTaskObject = { taskUid: number; diff --git a/src/utils.ts b/src/utils.ts index b5de6d680..7e8623faa 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,15 +1,3 @@ -/** Removes undefined entries from object */ -function removeUndefinedFromObject(obj: Record): object { - return Object.entries(obj).reduce( - (acc, curEntry) => { - const [key, val] = curEntry; - if (val !== undefined) acc[key] = val; - return acc; - }, - {} as Record, - ); -} - async function sleep(ms: number): Promise { return await new Promise((resolve) => setTimeout(resolve, ms)); } @@ -34,10 +22,4 @@ function validateUuid4(uuid: string): boolean { return regexExp.test(uuid); } -export { - sleep, - removeUndefinedFromObject, - addProtocolIfNotPresent, - addTrailingSlash, - validateUuid4, -}; +export { sleep, addProtocolIfNotPresent, addTrailingSlash, validateUuid4 }; diff --git a/tests/client.test.ts b/tests/client.test.ts index be593ef62..b743c648b 100644 --- a/tests/client.test.ts +++ b/tests/client.test.ts @@ -1,4 +1,14 @@ -import { afterAll, expect, test, describe, beforeEach } from "vitest"; +import { + afterAll, + expect, + test, + describe, + beforeEach, + vi, + type MockInstance, + beforeAll, + assert, +} from "vitest"; import { ErrorStatusCode, Health, Version, Stats, TaskTypes } from "../src"; import { PACKAGE_VERSION } from "../src/package-version"; import { @@ -50,54 +60,85 @@ describe.each([ expect(health).toBe(true); }); - test(`${permission} key: Create client with custom headers (object)`, async () => { - const key = await getKey(permission); - const client = new MeiliSearch({ - ...config, - apiKey: key, - requestInit: { - headers: { - "Hello-There!": "General Kenobi", + describe("Header tests", () => { + let fetchSpy: MockInstance; + + beforeAll(() => { + fetchSpy = vi.spyOn(globalThis, "fetch"); + }); + + afterAll(() => fetchSpy.mockRestore()); + + test(`${permission} key: Create client with custom headers (object)`, async () => { + const key = await getKey(permission); + const client = new MeiliSearch({ + ...config, + apiKey: key, + requestInit: { + headers: { + "Hello-There!": "General Kenobi", + }, }, - }, + }); + + assert.isTrue(await client.isHealthy()); + + assert.isDefined(fetchSpy.mock.lastCall); + const [, requestInit] = fetchSpy.mock.lastCall!; + + assert.isDefined(requestInit?.headers); + assert.instanceOf(requestInit!.headers, Headers); + assert.strictEqual( + (requestInit!.headers! as Headers).get("Hello-There!"), + "General Kenobi", + ); }); - expect(client.httpRequest.requestInit.headers.get("Hello-There!")).toBe( - "General Kenobi", - ); - const health = await client.isHealthy(); - expect(health).toBe(true); - }); - test(`${permission} key: Create client with custom headers (array)`, async () => { - const key = await getKey(permission); - const client = new MeiliSearch({ - ...config, - apiKey: key, - requestInit: { - headers: [["Hello-There!", "General Kenobi"]], - }, + test(`${permission} key: Create client with custom headers (array)`, async () => { + const key = await getKey(permission); + const client = new MeiliSearch({ + ...config, + apiKey: key, + requestInit: { + headers: [["Hello-There!", "General Kenobi"]], + }, + }); + + assert.isTrue(await client.isHealthy()); + + assert.isDefined(fetchSpy.mock.lastCall); + const [, requestInit] = fetchSpy.mock.lastCall!; + + assert.isDefined(requestInit?.headers); + assert.instanceOf(requestInit!.headers, Headers); + assert.strictEqual( + (requestInit!.headers! as Headers).get("Hello-There!"), + "General Kenobi", + ); }); - expect(client.httpRequest.requestInit.headers.get("Hello-There!")).toBe( - "General Kenobi", - ); - const health = await client.isHealthy(); - expect(health).toBe(true); - }); - test(`${permission} key: Create client with custom headers (Headers)`, async () => { - const key = await getKey(permission); - const headers = new Headers(); - headers.set("Hello-There!", "General Kenobi"); - const client = new MeiliSearch({ - ...config, - apiKey: key, - requestInit: { headers }, + test(`${permission} key: Create client with custom headers (Headers)`, async () => { + const key = await getKey(permission); + const headers = new Headers(); + headers.set("Hello-There!", "General Kenobi"); + const client = new MeiliSearch({ + ...config, + apiKey: key, + requestInit: { headers }, + }); + + assert.isTrue(await client.isHealthy()); + + assert.isDefined(fetchSpy.mock.lastCall); + const [, requestInit] = fetchSpy.mock.lastCall!; + + assert.isDefined(requestInit?.headers); + assert.instanceOf(requestInit!.headers, Headers); + assert.strictEqual( + (requestInit!.headers! as Headers).get("Hello-There!"), + "General Kenobi", + ); }); - expect(client.httpRequest.requestInit.headers.get("Hello-There!")).toBe( - "General Kenobi", - ); - const health = await client.isHealthy(); - expect(health).toBe(true); }); test(`${permission} key: No double slash when on host with domain and path and trailing slash`, async () => { @@ -259,47 +300,79 @@ describe.each([{ permission: "Master" }, { permission: "Admin" }])( expect(documents.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, - requestInit: { - headers: {}, - }, + describe("Header tests", () => { + let fetchSpy: MockInstance; + + beforeAll(() => { + fetchSpy = vi.spyOn(globalThis, "fetch"); }); - expect( - client.httpRequest.requestInit.headers.get("X-Meilisearch-Client"), - ).toStrictEqual(`Meilisearch JavaScript (v${PACKAGE_VERSION})`); - }); + afterAll(() => fetchSpy.mockRestore()); - test(`${permission} key: Create client with empty custom client agents`, async () => { - const key = await getKey(permission); - const client = new MeiliSearch({ - ...config, - apiKey: key, - clientAgents: [], + test(`${permission} key: Create client with no custom client agents`, async () => { + const key = await getKey(permission); + const client = new MeiliSearch({ + ...config, + apiKey: key, + requestInit: { + headers: {}, + }, + }); + + assert.isTrue(await client.isHealthy()); + + assert.isDefined(fetchSpy.mock.lastCall); + const [, requestInit] = fetchSpy.mock.lastCall!; + + assert.isDefined(requestInit?.headers); + assert.instanceOf(requestInit!.headers, Headers); + assert.strictEqual( + (requestInit!.headers! as Headers).get("X-Meilisearch-Client"), + `Meilisearch JavaScript (v${PACKAGE_VERSION})`, + ); }); - expect( - client.httpRequest.requestInit.headers.get("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: [], + }); - 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"], + assert.isTrue(await client.isHealthy()); + + assert.isDefined(fetchSpy.mock.lastCall); + const [, requestInit] = fetchSpy.mock.lastCall!; + + assert.isDefined(requestInit?.headers); + assert.instanceOf(requestInit!.headers, Headers); + assert.strictEqual( + (requestInit!.headers! as Headers).get("X-Meilisearch-Client"), + `Meilisearch JavaScript (v${PACKAGE_VERSION})`, + ); }); - expect( - client.httpRequest.requestInit.headers.get("X-Meilisearch-Client"), - ).toStrictEqual( - `random plugin 1 ; random plugin 2 ; 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"], + }); + + assert.isTrue(await client.isHealthy()); + + assert.isDefined(fetchSpy.mock.lastCall); + const [, requestInit] = fetchSpy.mock.lastCall!; + + assert.isDefined(requestInit?.headers); + assert.instanceOf(requestInit!.headers, Headers); + assert.strictEqual( + (requestInit!.headers! as Headers).get("X-Meilisearch-Client"), + `random plugin 1 ; random plugin 2 ; Meilisearch JavaScript (v${PACKAGE_VERSION})`, + ); + }); }); describe("Test on indexes methods", () => { diff --git a/tests/unit.test.ts b/tests/unit.test.ts index 3134974c5..bca78f807 100644 --- a/tests/unit.test.ts +++ b/tests/unit.test.ts @@ -1,27 +1,32 @@ -import { afterAll, expect, test } from "vitest"; +import { afterAll, assert, beforeAll, MockInstance, test, vi } from "vitest"; import { clearAllIndexes, config, MeiliSearch, } from "./utils/meilisearch-test-utils"; -afterAll(() => { - return clearAllIndexes(config); +let fetchSpy: MockInstance; + +beforeAll(() => { + fetchSpy = vi.spyOn(globalThis, "fetch"); }); -test(`Client handles host URL with domain and path`, () => { - const customHost = `${config.host}/api/`; - const client = new MeiliSearch({ - host: customHost, - }); - expect(client.config.host).toBe(customHost); - expect(client.httpRequest.url.href).toBe(customHost); +afterAll(async () => { + fetchSpy.mockRestore(); + await clearAllIndexes(config); }); -test(`Client handles host URL with domain and path and no trailing slash`, () => { +test(`Client handles host URL with domain and path, and adds trailing slash`, async () => { const customHost = `${config.host}/api`; - const client = new MeiliSearch({ - host: customHost, - }); - expect(client.httpRequest.url.href).toBe(customHost + "/"); + const client = new MeiliSearch({ host: customHost }); + + assert.strictEqual(client.config.host, customHost); + + assert.isTrue(await client.isHealthy()); + + assert.isDefined(fetchSpy.mock.lastCall); + const [input] = fetchSpy.mock.lastCall!; + + assert.instanceOf(input, URL); + assert.strictEqual((input as URL).href, `${customHost}/health`); }); diff --git a/tests/utils/meilisearch-test-utils.ts b/tests/utils/meilisearch-test-utils.ts index e2a9cb834..bfbab4258 100644 --- a/tests/utils/meilisearch-test-utils.ts +++ b/tests/utils/meilisearch-test-utils.ts @@ -78,7 +78,7 @@ const clearAllIndexes = async (config: Config): Promise => { const client = new MeiliSearch(config); const { results } = await client.getRawIndexes(); - const indexes = results.map((elem) => elem.uid); + const indexes = results.map(({ uid }) => uid); const taskIds: number[] = []; for (const indexUid of indexes) {