From 59fe7dbcace134a559c6a0127dc10cdcd9c4d2ff Mon Sep 17 00:00:00 2001 From: Dominik Dorfmeister Date: Mon, 10 Apr 2023 12:17:13 +0200 Subject: [PATCH 1/3] fix(core): make sure refetching multiple queries imperatively works offline --- packages/query-core/src/queryClient.ts | 11 ++++++---- .../query-core/src/tests/queryClient.test.tsx | 20 ++++++++++++++++++- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/packages/query-core/src/queryClient.ts b/packages/query-core/src/queryClient.ts index 9ca09d02bc..ea86a9892d 100644 --- a/packages/query-core/src/queryClient.ts +++ b/packages/query-core/src/queryClient.ts @@ -253,12 +253,15 @@ export class QueryClient { this.#queryCache .findAll(filters) .filter((query) => !query.isDisabled()) - .map((query) => - query.fetch(undefined, { + .map((query) => { + const promise = query.fetch(undefined, { ...options, cancelRefetch: options?.cancelRefetch ?? true, - }), - ), + }) + return query.state.fetchStatus === 'paused' + ? Promise.resolve() + : promise + }), ) let promise = Promise.all(promises).then(noop) diff --git a/packages/query-core/src/tests/queryClient.test.tsx b/packages/query-core/src/tests/queryClient.test.tsx index 51a55a67b7..4f81212c85 100644 --- a/packages/query-core/src/tests/queryClient.test.tsx +++ b/packages/query-core/src/tests/queryClient.test.tsx @@ -1,7 +1,12 @@ import { waitFor } from '@testing-library/react' import '@testing-library/jest-dom' -import { sleep, queryKey, createQueryClient } from './utils' +import { + sleep, + queryKey, + createQueryClient, + mockNavigatorOnLine, +} from './utils' import type { QueryCache, QueryClient, @@ -1020,6 +1025,19 @@ describe('queryClient', () => { } expect(error).toEqual('error') }) + + test('should resolve Promise immediately if query is paused', async () => { + const key1 = queryKey() + const queryFn1 = vi.fn().mockReturnValue('data1') + await queryClient.fetchQuery({ queryKey: key1, queryFn: queryFn1 }) + const onlineMock = mockNavigatorOnLine(false) + + await queryClient.refetchQueries({ queryKey: key1 }) + + // if we reach this point, the test succeeds because the Promise was resolved immediately + expect(queryFn1).toHaveBeenCalledTimes(1) + onlineMock.mockRestore() + }) }) describe('invalidateQueries', () => { From 58e4f90f5108845506bea3731338e1501cca01ec Mon Sep 17 00:00:00 2001 From: Dominik Dorfmeister Date: Mon, 10 Apr 2023 12:20:08 +0200 Subject: [PATCH 2/3] test: add another test for different networkMode --- packages/query-core/src/tests/queryClient.test.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/query-core/src/tests/queryClient.test.tsx b/packages/query-core/src/tests/queryClient.test.tsx index 4f81212c85..bde738afb8 100644 --- a/packages/query-core/src/tests/queryClient.test.tsx +++ b/packages/query-core/src/tests/queryClient.test.tsx @@ -1038,6 +1038,20 @@ describe('queryClient', () => { expect(queryFn1).toHaveBeenCalledTimes(1) onlineMock.mockRestore() }) + + test('should refetch if query we are offline but query networkMode is always', async () => { + const key1 = queryKey() + queryClient.setQueryDefaults(key1, { networkMode: 'always' }) + const queryFn1 = vi.fn().mockReturnValue('data1') + await queryClient.fetchQuery({ queryKey: key1, queryFn: queryFn1 }) + const onlineMock = mockNavigatorOnLine(false) + + await queryClient.refetchQueries({ queryKey: key1 }) + + // initial fetch + refetch (even though we are offline) + expect(queryFn1).toHaveBeenCalledTimes(2) + onlineMock.mockRestore() + }) }) describe('invalidateQueries', () => { From 215c42836d16009eafeadc376895909a67d26045 Mon Sep 17 00:00:00 2001 From: Dominik Dorfmeister Date: Mon, 10 Apr 2023 12:43:56 +0200 Subject: [PATCH 3/3] fix: always catch promises even if we don't return them because we are offline --- packages/query-core/src/queryClient.ts | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/query-core/src/queryClient.ts b/packages/query-core/src/queryClient.ts index ea86a9892d..0306302f1d 100644 --- a/packages/query-core/src/queryClient.ts +++ b/packages/query-core/src/queryClient.ts @@ -249,28 +249,26 @@ export class QueryClient { filters: RefetchQueryFilters = {}, options?: RefetchOptions, ): Promise { + const fetchOptions = { + ...options, + cancelRefetch: options?.cancelRefetch ?? true, + } const promises = notifyManager.batch(() => this.#queryCache .findAll(filters) .filter((query) => !query.isDisabled()) .map((query) => { - const promise = query.fetch(undefined, { - ...options, - cancelRefetch: options?.cancelRefetch ?? true, - }) + let promise = query.fetch(undefined, fetchOptions) + if (!fetchOptions.throwOnError) { + promise = promise.catch(noop) + } return query.state.fetchStatus === 'paused' ? Promise.resolve() : promise }), ) - let promise = Promise.all(promises).then(noop) - - if (!options?.throwOnError) { - promise = promise.catch(noop) - } - - return promise + return Promise.all(promises).then(noop) } fetchQuery<