diff --git a/src/createClient.ts b/src/createClient.ts index d47ddad3..5f1be367 100644 --- a/src/createClient.ts +++ b/src/createClient.ts @@ -90,16 +90,23 @@ export type FetchLike = ( export type AbortSignalLike = any; /** - * The minimum required properties from RequestInit. + * A subset of RequestInit properties to configure a `fetch()` request. */ -export interface RequestInitLike { +// Only options relevant to the client are included. Extending from the full +// RequestInit would cause issues, such as accepting Header objects. +// +// An interface is used to allow other libraries to augment the type with +// environment-specific types. +export interface RequestInitLike extends Pick { + /** + * An object literal to set the `fetch()` request's headers. + */ headers?: Record; /** - * An object that allows you to abort a `fetch()` request if needed via an - * `AbortController` object + * An AbortSignal to set the `fetch()` request's signal. * - * {@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal} + * See: \ */ // NOTE: `AbortSignalLike` is `any`! It is left as `AbortSignalLike` // for backwards compatibility (the type is exported) and to signal to @@ -259,18 +266,41 @@ export type ClientConfig = { * Node.js, this function must be provided. */ fetch?: FetchLike; + + /** + * Options provided to the client's `fetch()` on all network requests. + * These options will be merged with internally required options. They + * can also be overriden on a per-query basis using the query's + * `fetchOptions` parameter. + */ + fetchOptions?: RequestInitLike; }; /** - * Parameters for any client method that use `fetch()`. Only a subset of - * `fetch()` parameters are exposed. + * Parameters for any client method that use `fetch()`. */ type FetchParams = { + /** + * Options provided to the client's `fetch()` on all network requests. + * These options will be merged with internally required options. They + * can also be overriden on a per-query basis using the query's + * `fetchOptions` parameter. + */ + fetchOptions?: RequestInitLike; + /** * An `AbortSignal` provided by an `AbortController`. This allows the network * request to be cancelled if necessary. * * {@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal} + * + * @deprecated Move the `signal` parameter into `fetchOptions.signal`: + * + * ```typescript + * client.getByUID("page", "home",{ + * fetchOptions: { signal } + * }); + * ``` */ signal?: AbortSignalLike; }; @@ -409,6 +439,8 @@ export class Client { */ fetchFn: FetchLike; + fetchOptions?: RequestInitLike; + /** * Default parameters that will be sent with each query. These parameters can * be overridden on each query if needed. @@ -498,6 +530,7 @@ export class Client { this.accessToken = options.accessToken; this.routes = options.routes; this.brokenRoute = options.brokenRoute; + this.fetchOptions = options.fetchOptions; this.defaultParams = options.defaultParams; if (options.ref) { @@ -1328,12 +1361,15 @@ export class Client { */ async buildQueryURL({ signal, + fetchOptions, ...params }: Partial & FetchParams = {}): Promise { - const ref = params.ref || (await this.getResolvedRefString({ signal })); + const ref = + params.ref || (await this.getResolvedRefString({ signal, fetchOptions })); const integrationFieldsRef = params.integrationFieldsRef || - (await this.getCachedRepository({ signal })).integrationFieldsRef || + (await this.getCachedRepository({ signal, fetchOptions })) + .integrationFieldsRef || undefined; return buildQueryURL(this.endpoint, { @@ -1404,12 +1440,13 @@ export class Client { if (documentID != null && previewToken != null) { const document = await this.getByID(documentID, { - signal: args.signal, ref: previewToken, lang: "*", + signal: args.signal, + fetchOptions: args.fetchOptions, }); - const url = asLink(document, args.linkResolver); + const url = asLink(document, { linkResolver: args.linkResolver }); if (typeof url === "string") { return url; @@ -1737,6 +1774,19 @@ export class Client { url: string, params: FetchParams = {}, ): Promise { + const requestInit: RequestInitLike = { + ...this.fetchOptions, + ...params.fetchOptions, + headers: { + ...this.fetchOptions?.headers, + ...params.fetchOptions?.headers, + }, + signal: + params.fetchOptions?.signal || + params.signal || + this.fetchOptions?.signal, + }; + let job: Promise; // `fetchJobs` is keyed twice: first by the URL and again by is @@ -1744,15 +1794,13 @@ export class Client { // // Using two keys allows us to reuse fetch requests for // equivalent URLs, but eject when we detect unique signals. - if (this.fetchJobs[url] && this.fetchJobs[url].has(params.signal)) { + if (this.fetchJobs[url] && this.fetchJobs[url].has(requestInit.signal)) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - job = this.fetchJobs[url].get(params.signal)!; + job = this.fetchJobs[url].get(requestInit.signal)!; } else { this.fetchJobs[url] = this.fetchJobs[url] || new Map(); - job = this.fetchFn(url, { - signal: params.signal, - }) + job = this.fetchFn(url, requestInit) .then(async (res) => { // We can assume Prismic REST API responses // will have a `application/json` @@ -1773,14 +1821,14 @@ export class Client { }; }) .finally(() => { - this.fetchJobs[url].delete(params.signal); + this.fetchJobs[url].delete(requestInit.signal); if (this.fetchJobs[url].size === 0) { delete this.fetchJobs[url]; } }); - this.fetchJobs[url].set(params.signal, job); + this.fetchJobs[url].set(requestInit.signal, job); } const res = await job; diff --git a/test/__testutils__/testAbortableMethod.ts b/test/__testutils__/testAbortableMethod.ts index ae13f9ac..6b040ee9 100644 --- a/test/__testutils__/testAbortableMethod.ts +++ b/test/__testutils__/testAbortableMethod.ts @@ -8,7 +8,7 @@ import * as prismic from "../../src"; type TestAbortableMethodArgs = { run: ( client: prismic.Client, - signal: prismic.AbortSignalLike, + params?: Parameters[0], ) => Promise; }; @@ -25,7 +25,31 @@ export const testAbortableMethod = ( const client = createTestClient(); await expect(async () => { - await args.run(client, controller.signal); + await args.run(client, { + fetchOptions: { + signal: controller.signal, + }, + }); }).rejects.toThrow(/aborted/i); }); + + // TODO: Remove once the `signal` parameter is removed in favor of + // `fetchOptions.signal`. + it.concurrent( + `${description} (using deprecated \`signal\` param)`, + async (ctx) => { + const controller = new AbortController(); + controller.abort(); + + mockPrismicRestAPIV2({ ctx }); + + const client = createTestClient(); + + await expect(async () => { + await args.run(client, { + signal: controller.signal, + }); + }).rejects.toThrow(/aborted/i); + }, + ); }; diff --git a/test/__testutils__/testFetchOptions.ts b/test/__testutils__/testFetchOptions.ts new file mode 100644 index 00000000..e20b8616 --- /dev/null +++ b/test/__testutils__/testFetchOptions.ts @@ -0,0 +1,85 @@ +import { expect, it, vi } from "vitest"; + +import fetch from "node-fetch"; + +import { createTestClient } from "./createClient"; +import { mockPrismicRestAPIV2 } from "./mockPrismicRestAPIV2"; + +import * as prismic from "../../src"; + +type TestFetchOptionsArgs = { + run: ( + client: prismic.Client, + params?: Parameters[0], + ) => Promise; +}; + +export const testFetchOptions = ( + description: string, + args: TestFetchOptionsArgs, +): void => { + it.concurrent(`${description} (on client)`, async (ctx) => { + const abortController = new AbortController(); + + const fetchSpy = vi.fn(fetch); + const fetchOptions: prismic.RequestInitLike = { + cache: "no-store", + headers: { + foo: "bar", + }, + signal: abortController.signal, + }; + + mockPrismicRestAPIV2({ + ctx, + queryResponse: ctx.mock.api.query({ + documents: [ctx.mock.value.document()], + }), + }); + + const client = createTestClient({ + clientConfig: { + fetch: fetchSpy, + fetchOptions, + }, + }); + + await args.run(client); + + for (const [input, init] of fetchSpy.mock.calls) { + expect(init, input.toString()).toStrictEqual(fetchOptions); + } + }); + + it.concurrent(`${description} (on method)`, async (ctx) => { + const abortController = new AbortController(); + + const fetchSpy = vi.fn(fetch); + const fetchOptions: prismic.RequestInitLike = { + cache: "no-store", + headers: { + foo: "bar", + }, + signal: abortController.signal, + }; + + mockPrismicRestAPIV2({ + ctx, + queryResponse: ctx.mock.api.query({ + documents: [ctx.mock.value.document()], + }), + }); + + const client = createTestClient({ + clientConfig: { + fetch: fetchSpy, + }, + }); + + await args.run(client, { fetchOptions }); + + for (const [input, init] of fetchSpy.mock.calls) { + expect(init, input.toString()).toStrictEqual(fetchOptions); + } + }); +}; diff --git a/test/client-dangerouslyGetAll.test.ts b/test/client-dangerouslyGetAll.test.ts index 99ec09ed..eb6632be 100644 --- a/test/client-dangerouslyGetAll.test.ts +++ b/test/client-dangerouslyGetAll.test.ts @@ -6,6 +6,7 @@ import { mockPrismicRestAPIV2 } from "./__testutils__/mockPrismicRestAPIV2"; import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetAllMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; /** * The number of milliseconds in which a multi-page `getAll` (e.g. `getAll`, @@ -191,8 +192,12 @@ it("does not throttle single page queries", async (ctx) => { ).toBe(true); }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.dangerouslyGetAll(params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.dangerouslyGetAll({ signal }), + run: (client, params) => client.dangerouslyGetAll(params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-get.test.ts b/test/client-get.test.ts index a1f8f0d9..df73ee6f 100644 --- a/test/client-get.test.ts +++ b/test/client-get.test.ts @@ -6,7 +6,7 @@ import { createTestClient } from "./__testutils__/createClient"; import { mockPrismicRestAPIV2 } from "./__testutils__/mockPrismicRestAPIV2"; import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetMethod } from "./__testutils__/testAnyGetMethod"; -import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; testGetMethod("resolves a query", { run: (client) => client.get(), @@ -92,11 +92,10 @@ it("uses cached repository metadata within the client's repository cache TTL", a ); }); -testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.get({ signal }), +testFetchOptions("supports fetch options", { + run: (client, params) => client.get(params), }); -testConcurrentMethod("shares concurrent equivalent network requests", { +testAbortableMethod("is abortable with an AbortController", { run: (client, params) => client.get(params), - mode: "get", }); diff --git a/test/client-getAllByEveryTag.test.ts b/test/client-getAllByEveryTag.test.ts index 5fb8c70f..374fb601 100644 --- a/test/client-getAllByEveryTag.test.ts +++ b/test/client-getAllByEveryTag.test.ts @@ -1,6 +1,7 @@ import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetAllMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; testGetAllMethod("returns all documents by every tag from paginated response", { run: (client) => client.getAllByEveryTag(["foo", "bar"]), @@ -24,8 +25,12 @@ testGetAllMethod("includes params if provided", { }, }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getAllByEveryTag(["foo", "bar"], params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getAllByEveryTag(["foo", "bar"], { signal }), + run: (client, params) => client.getAllByEveryTag(["foo", "bar"], params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getAllByIDs.test.ts b/test/client-getAllByIDs.test.ts index 9e2d8881..cc53ca74 100644 --- a/test/client-getAllByIDs.test.ts +++ b/test/client-getAllByIDs.test.ts @@ -1,6 +1,7 @@ import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetAllMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; testGetAllMethod("returns all documents by IDs from paginated response", { run: (client) => client.getAllByIDs(["id1", "id2"]), @@ -24,8 +25,12 @@ testGetAllMethod("includes params if provided", { }, }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getAllByIDs(["id1", "id2"], params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getAllByIDs(["id1", "id2"], { signal }), + run: (client, params) => client.getAllByIDs(["id1", "id2"], params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getAllBySomeTags.test.ts b/test/client-getAllBySomeTags.test.ts index 47f73b84..a3b7934a 100644 --- a/test/client-getAllBySomeTags.test.ts +++ b/test/client-getAllBySomeTags.test.ts @@ -1,6 +1,7 @@ import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetAllMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; testGetAllMethod("returns all documents by some tags from paginated response", { run: (client) => client.getAllBySomeTags(["foo", "bar"]), @@ -24,8 +25,12 @@ testGetAllMethod("includes params if provided", { }, }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getAllBySomeTags(["foo", "bar"], params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getAllBySomeTags(["foo", "bar"], { signal }), + run: (client, params) => client.getAllBySomeTags(["foo", "bar"], params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getAllByTag.test.ts b/test/client-getAllByTag.test.ts index baf1a16f..995d81fd 100644 --- a/test/client-getAllByTag.test.ts +++ b/test/client-getAllByTag.test.ts @@ -1,6 +1,7 @@ import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetAllMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; testGetAllMethod("returns all documents by tag from paginated response", { run: (client) => client.getAllByTag("tag"), @@ -24,8 +25,12 @@ testGetAllMethod("includes params if provided", { }, }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getAllByTag("tag", params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getAllByTag("tag", { signal }), + run: (client, params) => client.getAllByTag("tag", params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getAllByType.test.ts b/test/client-getAllByType.test.ts index eef58621..2fad65b6 100644 --- a/test/client-getAllByType.test.ts +++ b/test/client-getAllByType.test.ts @@ -1,6 +1,7 @@ import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetAllMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; testGetAllMethod("returns all documents by type from paginated response", { run: (client) => client.getAllByType("type"), @@ -24,8 +25,12 @@ testGetAllMethod("includes params if provided", { }, }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getAllByType("type", params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getAllByType("type", { signal }), + run: (client, params) => client.getAllByType("type", params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getAllByUIDs.test.ts b/test/client-getAllByUIDs.test.ts index e65a488d..b23206a5 100644 --- a/test/client-getAllByUIDs.test.ts +++ b/test/client-getAllByUIDs.test.ts @@ -1,6 +1,7 @@ import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetAllMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; testGetAllMethod("returns all documents by UIDs from paginated response", { run: (client) => client.getAllByUIDs("type", ["uid1", "uid2"]), @@ -30,9 +31,14 @@ testGetAllMethod("includes params if provided", { }, }); +testFetchOptions("supports fetch options", { + run: (client, params) => + client.getAllByUIDs("type", ["uid1", "uid2"], params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => - client.getAllByUIDs("type", ["uid1", "uid2"], { signal }), + run: (client, params) => + client.getAllByUIDs("type", ["uid1", "uid2"], params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getByEveryTag.test.ts b/test/client-getByEveryTag.test.ts index 1d3f80a7..5c052fa7 100644 --- a/test/client-getByEveryTag.test.ts +++ b/test/client-getByEveryTag.test.ts @@ -1,6 +1,7 @@ import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; testGetMethod("queries for documents by tag", { run: (client) => client.getByEveryTag(["foo", "bar"]), @@ -24,8 +25,12 @@ testGetMethod("includes params if provided", { }, }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getByEveryTag(["foo", "bar"], params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getByEveryTag(["foo", "bar"], { signal }), + run: (client, params) => client.getByEveryTag(["foo", "bar"], params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getByID.test.ts b/test/client-getByID.test.ts index 35a9ee61..e0897007 100644 --- a/test/client-getByID.test.ts +++ b/test/client-getByID.test.ts @@ -1,6 +1,7 @@ import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetFirstMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; testGetFirstMethod("queries for document by ID", { run: (client) => client.getByID("id"), @@ -24,8 +25,12 @@ testGetFirstMethod("includes params if provided", { }, }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getByID("id", params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getByID("id", { signal }), + run: (client, params) => client.getByID("id", params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getByIDs.test.ts b/test/client-getByIDs.test.ts index eda64753..c6dbd72c 100644 --- a/test/client-getByIDs.test.ts +++ b/test/client-getByIDs.test.ts @@ -1,6 +1,7 @@ import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; testGetMethod("queries for documents by IDs", { run: (client) => client.getByIDs(["id1", "id2"]), @@ -24,8 +25,12 @@ testGetMethod("includes params if provided", { }, }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getByIDs(["id1", "id2"], params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getByIDs(["id1", "id2"], { signal }), + run: (client, params) => client.getByIDs(["id1", "id2"], params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getBySomeTags.test.ts b/test/client-getBySomeTags.test.ts index bc1eccff..f537f71a 100644 --- a/test/client-getBySomeTags.test.ts +++ b/test/client-getBySomeTags.test.ts @@ -1,6 +1,7 @@ import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; testGetMethod("queries for documents by some tags", { run: (client) => client.getBySomeTags(["foo", "bar"]), @@ -24,8 +25,12 @@ testGetMethod("includes params if provided", { }, }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getBySomeTags(["foo", "bar"], params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getBySomeTags(["foo", "bar"], { signal }), + run: (client, params) => client.getBySomeTags(["foo", "bar"], params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getByTag.test.ts b/test/client-getByTag.test.ts index c0c4dcea..5af1688e 100644 --- a/test/client-getByTag.test.ts +++ b/test/client-getByTag.test.ts @@ -1,6 +1,7 @@ import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; testGetMethod("queries for documents by tag", { run: (client) => client.getByTag("tag"), @@ -24,8 +25,12 @@ testGetMethod("includes params if provided", { }, }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getByTag("tag", params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getByTag("tag", { signal }), + run: (client, params) => client.getByTag("tag", params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getByType.test.ts b/test/client-getByType.test.ts index def92922..0b626724 100644 --- a/test/client-getByType.test.ts +++ b/test/client-getByType.test.ts @@ -1,6 +1,7 @@ import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; testGetMethod("queries for documents by type", { run: (client) => client.getByType("type"), @@ -24,8 +25,12 @@ testGetMethod("includes params if provided", { }, }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getByType("type", params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getByType("type", { signal }), + run: (client, params) => client.getByType("type", params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getByUID.test.ts b/test/client-getByUID.test.ts index 3bd5e554..e1a9e842 100644 --- a/test/client-getByUID.test.ts +++ b/test/client-getByUID.test.ts @@ -1,6 +1,7 @@ import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetFirstMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; testGetFirstMethod("queries for document by UID", { run: (client) => client.getByUID("type", "uid"), @@ -24,8 +25,12 @@ testGetFirstMethod("includes params if provided", { }, }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getByUID("type", "uid", params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getByUID("type", "uid", { signal }), + run: (client, params) => client.getByUID("type", "uid", params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getByUIDs.test.ts b/test/client-getByUIDs.test.ts index 0f9dc629..5976fcec 100644 --- a/test/client-getByUIDs.test.ts +++ b/test/client-getByUIDs.test.ts @@ -1,6 +1,7 @@ import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; testGetMethod("queries for documents by UIDs", { run: (client) => client.getByUIDs("type", ["uid1", "uid2"]), @@ -30,9 +31,12 @@ testGetMethod("includes params if provided", { }, }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getByUIDs("type", ["uid1", "uid2"], params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => - client.getByUIDs("type", ["uid1", "uid2"], { signal }), + run: (client, params) => client.getByUIDs("type", ["uid1", "uid2"], params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getFirst.test.ts b/test/client-getFirst.test.ts index 84d652cf..41045ca9 100644 --- a/test/client-getFirst.test.ts +++ b/test/client-getFirst.test.ts @@ -7,6 +7,7 @@ import { mockPrismicRestAPIV2 } from "./__testutils__/mockPrismicRestAPIV2"; import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetFirstMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; import * as prismic from "../src"; @@ -93,8 +94,12 @@ it("throws if no documents were returned", async (ctx) => { ); }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getFirst(params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getFirst({ signal }), + run: (client, params) => client.getFirst(params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getMasterRef.test.ts b/test/client-getMasterRef.test.ts index bc6cd668..98bae2fa 100644 --- a/test/client-getMasterRef.test.ts +++ b/test/client-getMasterRef.test.ts @@ -4,6 +4,7 @@ import { createTestClient } from "./__testutils__/createClient"; import { mockPrismicRestAPIV2 } from "./__testutils__/mockPrismicRestAPIV2"; import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; it("returns the master ref", async (ctx) => { const masterRef = ctx.mock.api.ref({ isMasterRef: true }); @@ -22,8 +23,12 @@ it("returns the master ref", async (ctx) => { expect(res).toStrictEqual(masterRef); }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getMasterRef(params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getMasterRef({ signal }), + run: (client, params) => client.getMasterRef(params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getRefByID.test.ts b/test/client-getRefByID.test.ts index 90a1a83b..4a2e45a7 100644 --- a/test/client-getRefByID.test.ts +++ b/test/client-getRefByID.test.ts @@ -4,6 +4,7 @@ import { createTestClient } from "./__testutils__/createClient"; import { mockPrismicRestAPIV2 } from "./__testutils__/mockPrismicRestAPIV2"; import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; import * as prismic from "../src"; @@ -38,8 +39,12 @@ it("throws if ref could not be found", async (ctx) => { ); }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getRefByID("id", params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getRefByID("id", { signal }), + run: (client, params) => client.getRefByID("id", params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getRefByLabel.test.ts b/test/client-getRefByLabel.test.ts index be6284ab..fa45747f 100644 --- a/test/client-getRefByLabel.test.ts +++ b/test/client-getRefByLabel.test.ts @@ -4,6 +4,7 @@ import { createTestClient } from "./__testutils__/createClient"; import { mockPrismicRestAPIV2 } from "./__testutils__/mockPrismicRestAPIV2"; import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; import * as prismic from "../src"; @@ -38,8 +39,12 @@ it("throws if ref could not be found", async (ctx) => { ); }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getRefByLabel("label", params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getRefByLabel("label", { signal }), + run: (client, params) => client.getRefByLabel("label", params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getRefs.test.ts b/test/client-getRefs.test.ts index 08e6a3ac..f140d62c 100644 --- a/test/client-getRefs.test.ts +++ b/test/client-getRefs.test.ts @@ -4,6 +4,7 @@ import { createTestClient } from "./__testutils__/createClient"; import { mockPrismicRestAPIV2 } from "./__testutils__/mockPrismicRestAPIV2"; import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; it("returns all refs", async (ctx) => { const repositoryResponse = ctx.mock.api.repository(); @@ -18,8 +19,12 @@ it("returns all refs", async (ctx) => { expect(res).toStrictEqual(repositoryResponse.refs); }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getRefs(params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getRefs({ signal }), + run: (client, params) => client.getRefs(params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getReleaseById.test.ts b/test/client-getReleaseById.test.ts index 1ec4da54..a9f7f752 100644 --- a/test/client-getReleaseById.test.ts +++ b/test/client-getReleaseById.test.ts @@ -4,6 +4,7 @@ import { createTestClient } from "./__testutils__/createClient"; import { mockPrismicRestAPIV2 } from "./__testutils__/mockPrismicRestAPIV2"; import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; import * as prismic from "../src"; @@ -36,8 +37,12 @@ it("throws if Release could not be found", async (ctx) => { ).rejects.toThrowError(prismic.PrismicError); }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getReleaseByID("id", params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getReleaseByID("id", { signal }), + run: (client, params) => client.getReleaseByID("id", params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getReleaseByLabel.test.ts b/test/client-getReleaseByLabel.test.ts index 0d2abdd1..25ec9fdc 100644 --- a/test/client-getReleaseByLabel.test.ts +++ b/test/client-getReleaseByLabel.test.ts @@ -4,6 +4,7 @@ import { createTestClient } from "./__testutils__/createClient"; import { mockPrismicRestAPIV2 } from "./__testutils__/mockPrismicRestAPIV2"; import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; import * as prismic from "../src"; @@ -36,8 +37,12 @@ it("throws if Release could not be found", async (ctx) => { ).rejects.toThrowError(prismic.PrismicError); }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getReleaseByLabel("label", params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getReleaseByLabel("label", { signal }), + run: (client, params) => client.getReleaseByLabel("label", params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getReleases.test.ts b/test/client-getReleases.test.ts index 5dbe8eaa..062729c1 100644 --- a/test/client-getReleases.test.ts +++ b/test/client-getReleases.test.ts @@ -4,6 +4,7 @@ import { createTestClient } from "./__testutils__/createClient"; import { mockPrismicRestAPIV2 } from "./__testutils__/mockPrismicRestAPIV2"; import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; it("returns all Releases", async (ctx) => { const repositoryResponse = ctx.mock.api.repository(); @@ -20,8 +21,12 @@ it("returns all Releases", async (ctx) => { ); }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getReleases(params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getReleases({ signal }), + run: (client, params) => client.getReleases(params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getRepository.test.ts b/test/client-getRepository.test.ts index 65f12ebe..54ce5331 100644 --- a/test/client-getRepository.test.ts +++ b/test/client-getRepository.test.ts @@ -3,7 +3,7 @@ import { expect, it } from "vitest"; import { createTestClient } from "./__testutils__/createClient"; import { mockPrismicRestAPIV2 } from "./__testutils__/mockPrismicRestAPIV2"; import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; -import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; import * as prismic from "../src"; @@ -39,11 +39,10 @@ it("includes access token if configured", async (ctx) => { expect(res).toStrictEqual(repositoryResponse); }); -testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getRepository({ signal }), +testFetchOptions("supports fetch options", { + run: (client, params) => client.getRepository(params), }); -testConcurrentMethod("shares concurrent equivalent network requests", { +testAbortableMethod("is abortable with an AbortController", { run: (client, params) => client.getRepository(params), - mode: "repository", }); diff --git a/test/client-getSingle.test.ts b/test/client-getSingle.test.ts index 303dc60b..20b94f51 100644 --- a/test/client-getSingle.test.ts +++ b/test/client-getSingle.test.ts @@ -1,6 +1,7 @@ import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testGetFirstMethod } from "./__testutils__/testAnyGetMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; testGetFirstMethod("queries for singleton document", { run: (client) => client.getSingle("type"), @@ -24,8 +25,12 @@ testGetFirstMethod("includes params if provided", { }, }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getSingle("type", params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getSingle("type", { signal }), + run: (client, params) => client.getSingle("type", params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-getTags.test.ts b/test/client-getTags.test.ts index 936a1ff0..18162bd7 100644 --- a/test/client-getTags.test.ts +++ b/test/client-getTags.test.ts @@ -6,6 +6,7 @@ import { createTestClient } from "./__testutils__/createClient"; import { mockPrismicRestAPIV2 } from "./__testutils__/mockPrismicRestAPIV2"; import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; it("returns all tags", async (ctx) => { const repositoryResponse = ctx.mock.api.repository(); @@ -81,8 +82,12 @@ it("sends access token if form endpoint is used", async (ctx) => { expect(res).toStrictEqual(tagsResponse); }); +testFetchOptions("supports fetch options", { + run: (client, params) => client.getTags(params), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => client.getTags({ signal }), + run: (client, params) => client.getTags(params), }); testConcurrentMethod("shares concurrent equivalent network requests", { diff --git a/test/client-graphQLFetch.test.ts b/test/client-graphQLFetch.test.ts index 47419e7b..9e5385ed 100644 --- a/test/client-graphQLFetch.test.ts +++ b/test/client-graphQLFetch.test.ts @@ -7,7 +7,6 @@ import { createTestClient } from "./__testutils__/createClient"; import { createRepositoryName } from "./__testutils__/createRepositoryName"; import { getMasterRef } from "./__testutils__/getMasterRef"; import { mockPrismicRestAPIV2 } from "./__testutils__/mockPrismicRestAPIV2"; -import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; it("resolves a query", async (ctx) => { @@ -205,11 +204,21 @@ it("includes a ref URL parameter to cache-bust", async (ctx) => { expect(json).toStrictEqual(graphqlResponse); }); -testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => - client.graphQLFetch("https://foo.cdn.prismic.io/graphql", { - signal, - }), +// `graphQLFetch()` uses a different function signature from query methods, so +// we cannot use the generalized `testAbortableMethod()` test util. +it("is abortable with an AbortController", async (ctx) => { + const controller = new AbortController(); + controller.abort(); + + mockPrismicRestAPIV2({ ctx }); + + const client = createTestClient(); + + await expect(async () => { + await client.graphQLFetch("https://foo.cdn.prismic.io/graphql", { + signal: controller.signal, + }); + }).rejects.toThrow(/aborted/i); }); testConcurrentMethod("does not share concurrent equivalent network requests", { diff --git a/test/client-resolvePreviewUrl.test.ts b/test/client-resolvePreviewUrl.test.ts index 9634259f..86920b93 100644 --- a/test/client-resolvePreviewUrl.test.ts +++ b/test/client-resolvePreviewUrl.test.ts @@ -7,6 +7,7 @@ import { createTestClient } from "./__testutils__/createClient"; import { mockPrismicRestAPIV2 } from "./__testutils__/mockPrismicRestAPIV2"; import { testAbortableMethod } from "./__testutils__/testAbortableMethod"; import { testConcurrentMethod } from "./__testutils__/testConcurrentMethod"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; const previewToken = "previewToken"; @@ -255,10 +256,20 @@ it("returns defaultURL if resolved URL is not a string", async (ctx) => { expect(res).toBe(defaultURL); }); +testFetchOptions("supports fetch options", { + run: (client, params) => + client.resolvePreviewURL({ + ...params, + defaultURL: "defaultURL", + documentID: "foo", + previewToken, + }), +}); + testAbortableMethod("is abortable with an AbortController", { - run: (client, signal) => + run: (client, params) => client.resolvePreviewURL({ - signal, + ...params, defaultURL: "defaultURL", documentID: "foo", previewToken,