From 394b003c9f878cca8fafa010854623938d7dd2e8 Mon Sep 17 00:00:00 2001 From: Wonsuk Choi Date: Tue, 3 Feb 2026 23:59:24 +0900 Subject: [PATCH] test(react-query/QueryResetErrorBoundary): relocate 'issue-9728' test and migrate to fake timers --- .../QueryResetErrorBoundary.test.tsx | 78 +++++++++++++ .../src/__tests__/issue-9728.test.tsx | 108 ------------------ 2 files changed, 78 insertions(+), 108 deletions(-) delete mode 100644 packages/react-query/src/__tests__/issue-9728.test.tsx diff --git a/packages/react-query/src/__tests__/QueryResetErrorBoundary.test.tsx b/packages/react-query/src/__tests__/QueryResetErrorBoundary.test.tsx index c02adeeece..f1506fb0e2 100644 --- a/packages/react-query/src/__tests__/QueryResetErrorBoundary.test.tsx +++ b/packages/react-query/src/__tests__/QueryResetErrorBoundary.test.tsx @@ -725,6 +725,84 @@ describe('QueryErrorResetBoundary', () => { consoleMock.mockRestore() }) + + it('should refetch after error when staleTime is Infinity and previous data exists (#9728)', async () => { + const key = queryKey() + const queryFn = vi.fn() + let count = 0 + + queryFn.mockImplementation(async () => { + await sleep(10) + count++ + if (count === 2) { + throw new Error('Error ' + count) + } + return 'Success ' + count + }) + + function Page() { + const [_, forceUpdate] = React.useState(0) + + React.useEffect(() => { + forceUpdate(1) + }, []) + + const { data, refetch } = useQuery({ + queryKey: key, + queryFn, + retry: false, + staleTime: Infinity, + throwOnError: true, + }) + + return ( +
+
Data: {data}
+ +
+ ) + } + + const rendered = renderWithClient( + queryClient, + + + {({ reset }) => ( + ( +
+
Status: error
+ +
+ )} + > + +
+ )} +
+
, + ) + + // 1. First mount -> fetching -> Success + await vi.advanceTimersByTimeAsync(11) + expect(rendered.getByText('Data: Success 1')).toBeInTheDocument() + expect(queryFn).toHaveBeenCalledTimes(1) + + // 2. Click Refetch -> Triggers fetch -> Fails (Error 2) -> ErrorBoundary + fireEvent.click(rendered.getByText('Refetch')) + await vi.advanceTimersByTimeAsync(11) + expect(rendered.getByText('Status: error')).toBeInTheDocument() + expect(queryFn).toHaveBeenCalledTimes(2) + + // 3. Click Retry -> Remounts + // Because staleTime is Infinity and we have Data from (1), + // AND we are in Error state. + fireEvent.click(rendered.getByText('Retry')) + await vi.advanceTimersByTimeAsync(11) + expect(rendered.getByText('Data: Success 3')).toBeInTheDocument() + expect(queryFn).toHaveBeenCalledTimes(3) + }) }) describe('useQueries', () => { diff --git a/packages/react-query/src/__tests__/issue-9728.test.tsx b/packages/react-query/src/__tests__/issue-9728.test.tsx deleted file mode 100644 index 44f3241cc8..0000000000 --- a/packages/react-query/src/__tests__/issue-9728.test.tsx +++ /dev/null @@ -1,108 +0,0 @@ -// @vitest-environment jsdom -import { describe, expect, it, vi } from 'vitest' -import { fireEvent, render } from '@testing-library/react' -import * as React from 'react' -import { ErrorBoundary } from 'react-error-boundary' -import { queryKey } from '@tanstack/query-test-utils' -import { - QueryClient, - QueryClientProvider, - QueryErrorResetBoundary, - useQuery, -} from '..' - -describe('issue 9728', () => { - it('should refetch after error when staleTime is Infinity and previous data exists', async () => { - const key = queryKey() - const queryFn = vi.fn() - let count = 0 - - queryFn.mockImplementation(async () => { - count++ - if (count === 2) { - throw new Error('Error ' + count) - } - return 'Success ' + count - }) - - const queryClient = new QueryClient({ - defaultOptions: { - queries: { - retry: false, - staleTime: Infinity, - }, - }, - }) - - function Page() { - const [_, forceUpdate] = React.useState(0) - - React.useEffect(() => { - forceUpdate(1) - }, []) - - const { data, refetch } = useQuery({ - queryKey: key, - queryFn, - throwOnError: true, - }) - - return ( -
-
Data: {data}
- -
- ) - } - - function App() { - return ( - - {({ reset }) => ( - ( -
-
Status: error
- -
- )} - > - Loading...}> - - -
- )} -
- ) - } - - const { getByText, findByText } = render( - - - - - , - ) - - // 1. First mount -> Success - await findByText('Data: Success 1') - expect(queryFn).toHaveBeenCalledTimes(1) - - // 2. Click Refetch -> Triggers fetch -> Fails (Error 2) -> ErrorBoundary - fireEvent.click(getByText('Refetch')) - - // Wait for error UI - await findByText('Status: error') - expect(queryFn).toHaveBeenCalledTimes(2) - - // 3. Click Retry -> Remounts - // Because staleTime is Infinity and we have Data from (1), - // AND we are in Error state. - fireEvent.click(getByText('Retry')) - - // Should call queryFn again (3rd time) and succeed - await findByText('Data: Success 3') - expect(queryFn).toHaveBeenCalledTimes(3) - }) -})