diff --git a/packages/react-query/src/__tests__/suspense.test.tsx b/packages/react-query/src/__tests__/suspense.test.tsx index 0a285fa6f4..cc8ae1fe7f 100644 --- a/packages/react-query/src/__tests__/suspense.test.tsx +++ b/packages/react-query/src/__tests__/suspense.test.tsx @@ -1,11 +1,55 @@ import { act, render, waitFor } from '@testing-library/react' import { Suspense } from 'react' -import { beforeEach, describe, expect, it } from 'vitest' +import { + afterAll, + beforeAll, + beforeEach, + describe, + expect, + it, + vi, +} from 'vitest' import { QueryClient, QueryClientProvider, useSuspenseQuery } from '..' -import { queryKey, renderWithClient, sleep } from './utils' +import { queryKey } from './utils' +import type { QueryKey } from '..' + +function renderWithSuspense(client: QueryClient, ui: React.ReactNode) { + return render( + + {ui} + , + ) +} + +function createTestQuery(options: { + fetchCount: { count: number } + queryKey: QueryKey + staleTime?: number | (() => number) +}) { + return function TestComponent() { + const { data } = useSuspenseQuery({ + queryKey: options.queryKey, + queryFn: () => { + options.fetchCount.count++ + return 'data' + }, + staleTime: options.staleTime, + }) + return
data: {data}
+ } +} describe('Suspense Timer Tests', () => { let queryClient: QueryClient + let fetchCount: { count: number } + + beforeAll(() => { + vi.useFakeTimers({ shouldAdvanceTime: true }) + }) + + afterAll(() => { + vi.useRealTimers() + }) beforeEach(() => { queryClient = new QueryClient({ @@ -15,37 +59,21 @@ describe('Suspense Timer Tests', () => { }, }, }) + fetchCount = { count: 0 } }) it('should enforce minimum staleTime of 1000ms when using suspense with number', async () => { - const shortStaleTime = 10 - let fetchCount = 0 - - function TestComponent() { - const { data } = useSuspenseQuery({ - queryKey: ['test'], - queryFn: () => { - fetchCount++ - return 'data' - }, - staleTime: shortStaleTime, - }) - return
{data}
- } + const TestComponent = createTestQuery({ + fetchCount, + queryKey: ['test'], + staleTime: 10, + }) - const wrapper = render( - - - - - , - ) + const rendered = renderWithSuspense(queryClient, ) - await waitFor(() => { - expect(wrapper.getByText('data')).toBeInTheDocument() - }) + await waitFor(() => rendered.getByText('data: data')) - wrapper.rerender( + rendered.rerender( @@ -53,42 +81,25 @@ describe('Suspense Timer Tests', () => { , ) - await act(async () => { - await new Promise((resolve) => setTimeout(resolve, 100)) + act(() => { + vi.advanceTimersByTime(100) }) - expect(fetchCount).toBe(1) + expect(fetchCount.count).toBe(1) }) it('should enforce minimum staleTime of 1000ms when using suspense with function', async () => { - let fetchCount = 0 - const staleTimeFunc = () => 10 - - function TestComponent() { - const { data } = useSuspenseQuery({ - queryKey: ['test-func'], - queryFn: () => { - fetchCount++ - return 'data' - }, - staleTime: staleTimeFunc, - }) - return
{data}
- } + const TestComponent = createTestQuery({ + fetchCount, + queryKey: ['test-func'], + staleTime: () => 10, + }) - const wrapper = render( - - - - - , - ) + const rendered = renderWithSuspense(queryClient, ) - await waitFor(() => { - expect(wrapper.getByText('data')).toBeInTheDocument() - }) + await waitFor(() => rendered.getByText('data: data')) - wrapper.rerender( + rendered.rerender( @@ -96,136 +107,88 @@ describe('Suspense Timer Tests', () => { , ) - await act(async () => { - await new Promise((resolve) => setTimeout(resolve, 100)) + act(() => { + vi.advanceTimersByTime(100) }) - expect(fetchCount).toBe(1) + expect(fetchCount.count).toBe(1) }) it('should respect staleTime when value is greater than 1000ms', async () => { - const key = queryKey() - const staleTime = 2000 - let fetchCount = 0 - - function Component() { - const result = useSuspenseQuery({ - queryKey: key, - queryFn: async () => { - fetchCount++ - await sleep(10) - return 'data' - }, - staleTime, - }) - return
data: {result.data}
- } - - const rendered = renderWithClient( - queryClient, - - - , - ) + const TestComponent = createTestQuery({ + fetchCount, + queryKey: queryKey(), + staleTime: 2000, + }) + + const rendered = renderWithSuspense(queryClient, ) await waitFor(() => rendered.getByText('data: data')) - // Manually trigger a remount rendered.rerender( - - - , + + + + + , ) - // Wait longer than 1000ms but less than staleTime - await act(async () => { - await sleep(1500) + act(() => { + vi.advanceTimersByTime(1500) }) - // Should not refetch as we're still within the staleTime - expect(fetchCount).toBe(1) + expect(fetchCount.count).toBe(1) }) it('should enforce minimum staleTime when undefined is provided', async () => { - const key = queryKey() - let fetchCount = 0 - - function Component() { - const result = useSuspenseQuery({ - queryKey: key, - queryFn: async () => { - fetchCount++ - await sleep(10) - return 'data' - }, - // Explicitly set staleTime as undefined - staleTime: undefined, - }) - return
data: {result.data}
- } - - const rendered = renderWithClient( - queryClient, - - - , - ) + const TestComponent = createTestQuery({ + fetchCount, + queryKey: queryKey(), + staleTime: undefined, + }) + + const rendered = renderWithSuspense(queryClient, ) await waitFor(() => rendered.getByText('data: data')) rendered.rerender( - - - , + + + + + , ) - // Wait less than enforced 1000ms - await act(async () => { - await sleep(500) + act(() => { + vi.advanceTimersByTime(500) }) - // Should not refetch as minimum staleTime of 1000ms is enforced - expect(fetchCount).toBe(1) + expect(fetchCount.count).toBe(1) }) it('should respect staleTime when function returns value greater than 1000ms', async () => { - const key = queryKey() - let fetchCount = 0 - - function Component() { - const result = useSuspenseQuery({ - queryKey: key, - queryFn: async () => { - fetchCount++ - await sleep(10) - return 'data' - }, - staleTime: () => 3000, - }) - return
data: {result.data}
- } - - const rendered = renderWithClient( - queryClient, - - - , - ) + const TestComponent = createTestQuery({ + fetchCount, + queryKey: queryKey(), + staleTime: () => 3000, + }) + + const rendered = renderWithSuspense(queryClient, ) await waitFor(() => rendered.getByText('data: data')) rendered.rerender( - - - , + + + + + , ) - // Wait longer than 1000ms but less than returned staleTime - await act(async () => { - await sleep(2000) + act(() => { + vi.advanceTimersByTime(2000) }) - // Should not refetch as we're still within the returned staleTime - expect(fetchCount).toBe(1) + expect(fetchCount.count).toBe(1) }) })