From bcad59de2b244a02f2ef39a00ff0de86dbe899d3 Mon Sep 17 00:00:00 2001 From: Thomas Vervest Date: Mon, 22 Jul 2024 09:41:52 +0200 Subject: [PATCH] chore: additional tests --- src/client.test.ts | 29 +++++++++++++++++++++++++++-- src/client.ts | 9 +++++---- src/server.test.ts | 24 +++++++++++++++++++++++- src/server.ts | 18 +++++++++++------- 4 files changed, 66 insertions(+), 14 deletions(-) diff --git a/src/client.test.ts b/src/client.test.ts index 35de0ff..b1131a2 100644 --- a/src/client.test.ts +++ b/src/client.test.ts @@ -60,6 +60,7 @@ describe("gqlClientFetch", () => { headers: { "Content-Type": "application/json", }, + signal: expect.any(AbortSignal), } ); }); @@ -84,7 +85,7 @@ describe("gqlClientFetch", () => { "Content-Type": "application/json", }, signal: expect.any(AbortSignal), - }, + } ); }); it("should perform a mutation", async () => { @@ -161,7 +162,7 @@ describe("gqlClientFetch", () => { it("should use the provided timeout duration", async () => { const fetcher = initClientFetcher("https://localhost/graphql", { - timeout: 1, + defaultTimeout: 1, }); const timeoutSpy = vi.spyOn(AbortSignal, "timeout"); fetchMock.mockResponse(responseString); @@ -175,4 +176,28 @@ describe("gqlClientFetch", () => { // It should not try to POST the query if the persisted query cannot be parsed expect(fetchMock).toHaveBeenCalledTimes(1); }); + + it("should use the provided signal", async () => { + const fetcher = initClientFetcher("https://localhost/graphql"); + fetchMock.mockResponse(responseString); + + const controller = new AbortController(); + await fetcher( + query, + { + myVar: "baz", + }, + controller.signal + ); + + expect(fetchMock).toHaveBeenCalledWith( + expect.any(String), + expect.objectContaining({ + signal: controller.signal, + }) + ); + + // It should not try to POST the query if the persisted query cannot be parsed + expect(fetchMock).toHaveBeenCalledTimes(1); + }); }); diff --git a/src/client.ts b/src/client.ts index 8443443..bc7821e 100644 --- a/src/client.ts +++ b/src/client.ts @@ -19,11 +19,11 @@ type Options = { persistedQueries?: boolean; /** - * Sets the timeout duration in ms after which a request will throw a timeout error + * Sets the default timeout duration in ms after which a request will throw a timeout error * * @default 30000 */ - timeout?: number; + defaultTimeout?: number; }; export type ClientFetcher = ( @@ -35,7 +35,7 @@ export type ClientFetcher = ( export const initClientFetcher = ( endpoint: string, - { persistedQueries = false, timeout = 30000 }: Options = {} + { persistedQueries = false, defaultTimeout = 30000 }: Options = {} ): ClientFetcher => /** * Executes a GraphQL query post request on the client. @@ -46,7 +46,7 @@ export const initClientFetcher = async ( astNode: DocumentTypeDecoration, variables?: TVariables, - signal: AbortSignal = AbortSignal.timeout(timeout) + signal: AbortSignal = AbortSignal.timeout(defaultTimeout) ): Promise> => { const query = astNode.toString(); @@ -94,6 +94,7 @@ export const initClientFetcher = method: "POST", body: JSON.stringify({ query, variables, extensions }), credentials: "include", + signal, }) ); } diff --git a/src/server.test.ts b/src/server.test.ts index 75e1f81..236bddb 100644 --- a/src/server.test.ts +++ b/src/server.test.ts @@ -46,6 +46,7 @@ describe("gqlServerFetch", () => { }, cache: "force-cache", next: { revalidate: 900 }, + signal: expect.any(AbortSignal), } ); }); @@ -119,6 +120,7 @@ describe("gqlServerFetch", () => { }, cache: "no-store", next: { revalidate: undefined }, + signal: expect.any(AbortSignal), } ); }); @@ -192,7 +194,7 @@ describe("gqlServerFetch", () => { it("should use the provided timeout duration", async () => { const timeoutSpy = vi.spyOn(AbortSignal, "timeout"); const gqlServerFetch = initServerFetcher("https://localhost/graphql", { - timeout: 1, + defaultTimeout: 1, }); fetchMock.mockResponse(successResponse); @@ -203,4 +205,24 @@ describe("gqlServerFetch", () => { // It should not try to POST the query if the persisted query cannot be parsed expect(fetchMock).toHaveBeenCalledTimes(1); }); + + it("should use the provided signal", async () => { + const gqlServerFetch = initServerFetcher("https://localhost/graphql", { + defaultTimeout: 1, + }); + fetchMock.mockResponse(successResponse); + + const controller = new AbortController(); + await gqlServerFetch(query, { myVar: "baz" }, {}, controller.signal); + + expect(fetchMock).toHaveBeenCalledWith( + expect.any(String), + expect.objectContaining({ + signal: controller.signal, + }) + ); + + // It should not try to POST the query if the persisted query cannot be parsed + expect(fetchMock).toHaveBeenCalledTimes(1); + }); }); diff --git a/src/server.ts b/src/server.ts index b2e84de..ae2e819 100644 --- a/src/server.ts +++ b/src/server.ts @@ -20,11 +20,11 @@ type Options = { dangerouslyDisableCache?: boolean; /** - * Sets the timeout duration in ms after which a request will throw a timeout error + * Sets the default timeout duration in ms after which a request will throw a timeout error * * @default 30000 */ - timeout?: number; + defaultTimeout?: number; }; type CacheOptions = { @@ -40,13 +40,13 @@ const tracer = trace.getTracer( export const initServerFetcher = ( url: string, - { dangerouslyDisableCache = false, timeout = 30000 }: Options = {} + { dangerouslyDisableCache = false, defaultTimeout = 30000 }: Options = {} ) => async ( astNode: DocumentTypeDecoration, variables: TVariables, { cache, next = {} }: CacheOptions, - signal: AbortSignal = AbortSignal.timeout(timeout) + signal: AbortSignal = AbortSignal.timeout(defaultTimeout) ): Promise> => { const query = astNode.toString(); const operationName = extractOperationName(query) || "(GraphQL)"; @@ -93,7 +93,8 @@ export const initServerFetcher = let response = await gqlPersistedQuery( url, getQueryString(operationName, variables, extensions), - { cache, next } + { cache, next }, + signal ); if (response.errors?.[0]?.message === "PersistedQueryNotFound") { @@ -101,7 +102,8 @@ export const initServerFetcher = response = await gqlPost( url, JSON.stringify({ operationName, query, variables, extensions }), - { cache, next } + { cache, next }, + signal ); } @@ -138,13 +140,15 @@ const gqlPost = async ( const gqlPersistedQuery = async ( url: string, queryString: URLSearchParams, - { cache, next }: CacheOptions + { cache, next }: CacheOptions, + signal: AbortSignal = AbortSignal.timeout(30000) ) => { const response = await fetch(`${url}?${queryString}`, { method: "GET", headers: defaultHeaders, cache, next, + signal, }); return parseResponse(response);