From 90d3f164f604ba8badb3fb5e7a6d4ba758ba7c3a Mon Sep 17 00:00:00 2001 From: Curt Grimes Date: Thu, 28 Jul 2022 23:27:51 -0500 Subject: [PATCH] fix(useFetch): broken callbacks when RequestInit and UseFetchOptions are both passed in When useFetch has 3 arguments (`url`, `RequestInit`, and `UseFetchOptions`), the `beforeFetch`, `afterFetch`, and `onFetchError` callbacks were not being passed through. After this commit, they are. Relevant unit tests are also added. fix #2012 --- packages/core/useFetch/index.test.ts | 75 ++++++++++++++++++++++++++++ packages/core/useFetch/index.ts | 11 +++- 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/packages/core/useFetch/index.test.ts b/packages/core/useFetch/index.test.ts index 647abe44705..2e8cba5d181 100644 --- a/packages/core/useFetch/index.test.ts +++ b/packages/core/useFetch/index.test.ts @@ -181,6 +181,81 @@ describe('useFetch', () => { }) }) + test('should chain beforeFetch function when using a factory instance and the options object in useMyFetch', async () => { + const useMyFetch = createFetch({ + baseUrl: 'https://example.com', + options: { + beforeFetch({ options }) { + options.headers = { ...options.headers, Global: 'foo' } + return { options } + }, + }, + }) + useMyFetch( + 'test', + { method: 'GET' }, + { + beforeFetch({ options }) { + options.headers = { ...options.headers, Local: 'foo' } + return { options } + }, + }) + + await retry(() => { + expect(fetchSpyHeaders()).toMatchObject({ Global: 'foo', Local: 'foo' }) + }) + }) + + test('should chain afterFetch function when using a factory instance and the options object in useMyFetch', async () => { + const useMyFetch = createFetch({ + baseUrl: 'https://example.com', + options: { + afterFetch(ctx) { + ctx.data.title = 'Global' + return ctx + }, + }, + }) + const { data } = useMyFetch( + 'test?json', + { method: 'GET' }, + { + afterFetch(ctx) { + ctx.data.title += ' Local' + return ctx + }, + }).json() + + await retry(() => { + expect(data.value).toEqual(expect.objectContaining({ title: 'Global Local' })) + }) + }) + + test('should chain onFetchError function when using a factory instance and the options object in useMyFetch', async () => { + const useMyFetch = createFetch({ + baseUrl: 'https://example.com', + options: { + onFetchError(ctx) { + ctx.data.title = 'Global' + return ctx + }, + }, + }) + const { data } = useMyFetch( + 'test?status=400&json', + { method: 'GET' }, + { + onFetchError(ctx) { + ctx.data.title += ' Local' + return ctx + }, + }).json() + + await retry(() => { + expect(data.value).toEqual(expect.objectContaining({ title: 'Global Local' })) + }) + }) + test('should run the beforeFetch function and add headers to the request', async () => { useFetch('https://example.com', { headers: { 'Accept-Language': 'en-US' } }, { beforeFetch({ options }) { diff --git a/packages/core/useFetch/index.ts b/packages/core/useFetch/index.ts index 02ef0d433c3..82397fc2ea3 100644 --- a/packages/core/useFetch/index.ts +++ b/packages/core/useFetch/index.ts @@ -260,8 +260,15 @@ export function createFetch(config: CreateFetchOptions = {}) { } } - if (args.length > 1 && isFetchOptions(args[1])) - options = { ...options, ...args[1] } + if (args.length > 1 && isFetchOptions(args[1])) { + options = { + ...options, + ...args[1], + beforeFetch: chainCallbacks(_options.beforeFetch, args[1].beforeFetch), + afterFetch: chainCallbacks(_options.afterFetch, args[1].afterFetch), + onFetchError: chainCallbacks(_options.onFetchError, args[1].onFetchError), + } + } return useFetch(computedUrl, fetchOptions, options) }