From 6e44b1b6b6611cc0f163a71308b74a0af7491d31 Mon Sep 17 00:00:00 2001 From: Luke Nelson Date: Mon, 20 Nov 2023 13:59:41 +0000 Subject: [PATCH] fix(nuxt): respect custom timeout in `useFetch` (#24364) --- docs/3.api/2.composables/use-fetch.md | 1 + packages/nuxt/src/app/composables/fetch.ts | 11 +++++++++++ test/nuxt/composables.test.ts | 10 ++++++++++ 3 files changed, 22 insertions(+) diff --git a/docs/3.api/2.composables/use-fetch.md b/docs/3.api/2.composables/use-fetch.md index be30417a07..b92f102fe5 100644 --- a/docs/3.api/2.composables/use-fetch.md +++ b/docs/3.api/2.composables/use-fetch.md @@ -80,6 +80,7 @@ const { data, pending, error, refresh } = await useFetch('/api/auth/login', { - `body`: Request body - automatically stringified (if an object is passed). - `headers`: Request headers. - `baseURL`: Base URL for the request. + - `timeout`: Milliseconds to automatically abort request ::callout All fetch options can be given a `computed` or `ref` value. These will be watched and new requests made automatically with any new values if they are updated. diff --git a/packages/nuxt/src/app/composables/fetch.ts b/packages/nuxt/src/app/composables/fetch.ts index 85256a59b2..07812d0928 100644 --- a/packages/nuxt/src/app/composables/fetch.ts +++ b/packages/nuxt/src/app/composables/fetch.ts @@ -140,6 +140,17 @@ export function useFetch< controller?.abort?.() controller = typeof AbortController !== 'undefined' ? new AbortController() : {} as AbortController + /** + * Workaround for `timeout` not working due to custom abort controller + * TODO: remove this when upstream issue is resolved + * @see https://github.com/unjs/ofetch/issues/326 + * @see https://github.com/unjs/ofetch/blob/bb2d72baa5d3f332a2185c20fc04e35d2c3e258d/src/fetch.ts#L152 + */ + const timeoutLength = toValue(opts.timeout) + if (timeoutLength) { + setTimeout(() => controller.abort(), timeoutLength) + } + let _$fetch = opts.$fetch || globalThis.$fetch // Use fetch with request context and headers for server direct API calls diff --git a/test/nuxt/composables.test.ts b/test/nuxt/composables.test.ts index fc80b96f98..431be1a7cb 100644 --- a/test/nuxt/composables.test.ts +++ b/test/nuxt/composables.test.ts @@ -266,6 +266,16 @@ describe('useFetch', () => { await useFetch('/api/test', { params: { id: ref('3') } }, '') expect.soft(getPayloadEntries()).toBe(baseCount + 3) }) + + it('should timeout', async () => { + const { status, error } = await useFetch( + () => new Promise(resolve => setTimeout(resolve, 5000)), + { timeout: 1 } + ) + await new Promise(resolve => setTimeout(resolve, 2)) + expect(status.value).toBe('error') + expect(error.value).toMatchInlineSnapshot('[Error: [GET] "[object Promise]": The operation was aborted.]') + }) }) describe('errors', () => {