diff --git a/packages/react-query-persist-client/src/__tests__/PersistQueryClientProvider.test.tsx b/packages/react-query-persist-client/src/__tests__/PersistQueryClientProvider.test.tsx index 74bccab533..10e6948405 100644 --- a/packages/react-query-persist-client/src/__tests__/PersistQueryClientProvider.test.tsx +++ b/packages/react-query-persist-client/src/__tests__/PersistQueryClientProvider.test.tsx @@ -1,6 +1,6 @@ -import { describe, expect, test, vi } from 'vitest' +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' import * as React from 'react' -import { fireEvent, render, waitFor } from '@testing-library/react' +import { act, fireEvent, render } from '@testing-library/react' import { QueryClient, useQueries, useQuery } from '@tanstack/react-query' import { persistQueryClientSave } from '@tanstack/query-persist-client-core' import { queryKey, sleep } from '@tanstack/query-test-utils' @@ -22,8 +22,7 @@ const createMockPersister = (): Persister => { storedState = persistClient }, async restoreClient() { - await sleep(10) - return storedState + return sleep(10).then(() => storedState) }, removeClient() { storedState = undefined @@ -51,29 +50,36 @@ const createMockErrorPersister = ( } describe('PersistQueryClientProvider', () => { + beforeEach(() => { + vi.useFakeTimers() + }) + + afterEach(() => { + vi.useRealTimers() + }) + test('restores cache from persister', async () => { const key = queryKey() const states: Array> = [] const queryClient = new QueryClient() - await queryClient.prefetchQuery({ + queryClient.prefetchQuery({ queryKey: key, - queryFn: () => Promise.resolve('hydrated'), + queryFn: () => sleep(10).then(() => 'hydrated'), }) + await vi.advanceTimersByTimeAsync(10) const persister = createMockPersister() - await persistQueryClientSave({ queryClient, persister }) + persistQueryClientSave({ queryClient, persister }) + await vi.advanceTimersByTimeAsync(0) queryClient.clear() function Page() { const state = useQuery({ queryKey: key, - queryFn: async () => { - await sleep(10) - return 'fetched' - }, + queryFn: () => sleep(10).then(() => 'fetched'), }) states.push(state) @@ -95,9 +101,11 @@ describe('PersistQueryClientProvider', () => { , ) - await waitFor(() => rendered.getByText('fetchStatus: idle')) - await waitFor(() => rendered.getByText('hydrated')) - await waitFor(() => rendered.getByText('fetched')) + expect(rendered.getByText('fetchStatus: idle')).toBeInTheDocument() + await act(() => vi.advanceTimersByTimeAsync(10)) + expect(rendered.getByText('hydrated')).toBeInTheDocument() + await act(() => vi.advanceTimersByTimeAsync(11)) + expect(rendered.getByText('fetched')).toBeInTheDocument() expect(states).toHaveLength(4) @@ -130,24 +138,23 @@ describe('PersistQueryClientProvider', () => { const key = queryKey() const queryClient = new QueryClient() - await queryClient.prefetchQuery({ + queryClient.prefetchQuery({ queryKey: key, - queryFn: () => Promise.resolve('hydrated'), + queryFn: () => sleep(10).then(() => 'hydrated'), }) + await vi.advanceTimersByTimeAsync(10) const persister = createMockPersister() - await persistQueryClientSave({ queryClient, persister }) + persistQueryClientSave({ queryClient, persister }) + await vi.advanceTimersByTimeAsync(0) queryClient.clear() function Page() { const state = useQuery({ queryKey: key, - queryFn: async () => { - await sleep(10) - return 'fetched' - }, + queryFn: () => sleep(10).then(() => 'fetched'), }) return ( @@ -177,15 +184,19 @@ describe('PersistQueryClientProvider', () => { , ) - await waitFor(() => rendered.getByText('fetchStatus: idle')) - await waitFor(() => rendered.getByText('hydrated')) - await waitFor(() => rendered.getByText('fetched')) + expect(rendered.getByText('fetchStatus: idle')).toBeInTheDocument() + await act(() => vi.advanceTimersByTimeAsync(10)) + expect(rendered.getByText('hydrated')).toBeInTheDocument() + await act(() => vi.advanceTimersByTimeAsync(11)) + expect(rendered.getByText('fetched')).toBeInTheDocument() fireEvent.click(rendered.getByRole('button', { name: /update/i })) + await act(() => vi.advanceTimersByTimeAsync(0)) + expect(rendered.getByText('updated')).toBeInTheDocument() - await waitFor(() => rendered.getByText('updated')) - - const state = await persister.restoreClient() + const statePromise = persister.restoreClient() + await act(() => vi.advanceTimersByTimeAsync(10)) + const state = await statePromise expect(state?.clientState.queries[0]?.state.data).toBe('updated') }) @@ -195,14 +206,16 @@ describe('PersistQueryClientProvider', () => { const states: Array = [] const queryClient = new QueryClient() - await queryClient.prefetchQuery({ + queryClient.prefetchQuery({ queryKey: key, - queryFn: () => Promise.resolve('hydrated'), + queryFn: () => sleep(10).then(() => 'hydrated'), }) + await vi.advanceTimersByTimeAsync(10) const persister = createMockPersister() - await persistQueryClientSave({ queryClient, persister }) + persistQueryClientSave({ queryClient, persister }) + await vi.advanceTimersByTimeAsync(0) queryClient.clear() @@ -211,10 +224,7 @@ describe('PersistQueryClientProvider', () => { queries: [ { queryKey: key, - queryFn: async (): Promise => { - await sleep(10) - return 'fetched' - }, + queryFn: () => sleep(10).then(() => 'fetched'), }, ], }) @@ -238,9 +248,11 @@ describe('PersistQueryClientProvider', () => { , ) - await waitFor(() => rendered.getByText('fetchStatus: idle')) - await waitFor(() => rendered.getByText('hydrated')) - await waitFor(() => rendered.getByText('fetched')) + expect(rendered.getByText('fetchStatus: idle')).toBeInTheDocument() + await act(() => vi.advanceTimersByTimeAsync(10)) + expect(rendered.getByText('hydrated')).toBeInTheDocument() + await act(() => vi.advanceTimersByTimeAsync(11)) + expect(rendered.getByText('fetched')).toBeInTheDocument() expect(states).toHaveLength(4) @@ -274,25 +286,23 @@ describe('PersistQueryClientProvider', () => { const states: Array> = [] const queryClient = new QueryClient() - await queryClient.prefetchQuery({ + queryClient.prefetchQuery({ queryKey: key, - queryFn: () => Promise.resolve('hydrated'), + queryFn: () => sleep(10).then(() => 'hydrated'), }) + await vi.advanceTimersByTimeAsync(10) const persister = createMockPersister() - await persistQueryClientSave({ queryClient, persister }) + persistQueryClientSave({ queryClient, persister }) + await vi.advanceTimersByTimeAsync(0) queryClient.clear() function Page() { const state = useQuery({ queryKey: key, - queryFn: async () => { - await sleep(10) - return 'fetched' - }, - + queryFn: () => sleep(10).then(() => 'fetched'), initialData: 'initial', // make sure that initial data is older than the hydration data // otherwise initialData would be newer and takes precedence @@ -318,9 +328,11 @@ describe('PersistQueryClientProvider', () => { , ) - await waitFor(() => rendered.getByText('initial')) - await waitFor(() => rendered.getByText('hydrated')) - await waitFor(() => rendered.getByText('fetched')) + expect(rendered.getByText('initial')).toBeInTheDocument() + await act(() => vi.advanceTimersByTimeAsync(10)) + expect(rendered.getByText('hydrated')).toBeInTheDocument() + await act(() => vi.advanceTimersByTimeAsync(11)) + expect(rendered.getByText('fetched')).toBeInTheDocument() expect(states).toHaveLength(4) @@ -354,14 +366,16 @@ describe('PersistQueryClientProvider', () => { const states: Array> = [] const queryClient = new QueryClient() - await queryClient.prefetchQuery({ + queryClient.prefetchQuery({ queryKey: key, - queryFn: () => Promise.resolve('hydrated'), + queryFn: () => sleep(10).then(() => 'hydrated'), }) + await vi.advanceTimersByTimeAsync(10) const persister = createMockPersister() - await persistQueryClientSave({ queryClient, persister }) + persistQueryClientSave({ queryClient, persister }) + await vi.advanceTimersByTimeAsync(0) queryClient.clear() @@ -370,11 +384,11 @@ describe('PersistQueryClientProvider', () => { function Page() { const state = useQuery({ queryKey: key, - queryFn: async () => { - fetched = true - await sleep(10) - return 'fetched' - }, + queryFn: () => + sleep(10).then(() => { + fetched = true + return 'fetched' + }), staleTime: Infinity, }) @@ -398,8 +412,9 @@ describe('PersistQueryClientProvider', () => { , ) - await waitFor(() => rendered.getByText('data: null')) - await waitFor(() => rendered.getByText('data: hydrated')) + expect(rendered.getByText('data: null')).toBeInTheDocument() + await act(() => vi.advanceTimersByTimeAsync(10)) + expect(rendered.getByText('data: hydrated')).toBeInTheDocument() expect(states).toHaveLength(2) @@ -422,24 +437,23 @@ describe('PersistQueryClientProvider', () => { const key = queryKey() const queryClient = new QueryClient() - await queryClient.prefetchQuery({ + queryClient.prefetchQuery({ queryKey: key, - queryFn: () => Promise.resolve('hydrated'), + queryFn: () => sleep(10).then(() => 'hydrated'), }) + await vi.advanceTimersByTimeAsync(10) const persister = createMockPersister() - await persistQueryClientSave({ queryClient, persister }) + persistQueryClientSave({ queryClient, persister }) + await vi.advanceTimersByTimeAsync(0) queryClient.clear() function Page() { const state = useQuery({ queryKey: key, - queryFn: async () => { - await sleep(10) - return 'fetched' - }, + queryFn: () => sleep(10).then(() => 'fetched'), }) return ( @@ -461,25 +475,30 @@ describe('PersistQueryClientProvider', () => { , ) + expect(onSuccess).toHaveBeenCalledTimes(0) - await waitFor(() => rendered.getByText('hydrated')) + await act(() => vi.advanceTimersByTimeAsync(10)) + expect(rendered.getByText('hydrated')).toBeInTheDocument() expect(onSuccess).toHaveBeenCalledTimes(1) - await waitFor(() => rendered.getByText('fetched')) + await act(() => vi.advanceTimersByTimeAsync(11)) + expect(rendered.getByText('fetched')).toBeInTheDocument() }) test('should await onSuccess after successful restoring', async () => { const key = queryKey() const queryClient = new QueryClient() - await queryClient.prefetchQuery({ + queryClient.prefetchQuery({ queryKey: key, - queryFn: () => Promise.resolve('hydrated'), + queryFn: () => sleep(10).then(() => 'hydrated'), }) + await vi.advanceTimersByTimeAsync(10) const persister = createMockPersister() - await persistQueryClientSave({ queryClient, persister }) + persistQueryClientSave({ queryClient, persister }) + await vi.advanceTimersByTimeAsync(0) queryClient.clear() @@ -518,8 +537,11 @@ describe('PersistQueryClientProvider', () => { , ) - await waitFor(() => rendered.getByText('hydrated')) - await waitFor(() => rendered.getByText('fetched')) + await act(() => vi.advanceTimersByTimeAsync(30)) + expect(rendered.getByText('hydrated')).toBeInTheDocument() + await act(() => vi.advanceTimersByTimeAsync(11)) + expect(rendered.getByText('fetched')).toBeInTheDocument() + expect(states).toEqual([ 'onSuccess', 'onSuccess done', @@ -546,10 +568,7 @@ describe('PersistQueryClientProvider', () => { function Page() { const state = useQuery({ queryKey: key, - queryFn: async () => { - await sleep(10) - return 'fetched' - }, + queryFn: () => sleep(10).then(() => 'fetched'), }) return ( @@ -571,7 +590,9 @@ describe('PersistQueryClientProvider', () => { , ) - await waitFor(() => rendered.getByText('fetched')) + await act(() => vi.advanceTimersByTimeAsync(10)) + await act(() => vi.advanceTimersByTimeAsync(11)) + expect(rendered.getByText('fetched')).toBeInTheDocument() expect(removeClient).toHaveBeenCalledTimes(1) expect(onSuccess).toHaveBeenCalledTimes(0) expect(onError).toHaveBeenCalledTimes(1) @@ -587,27 +608,27 @@ describe('PersistQueryClientProvider', () => { const states: Array = [] const queryClient = new QueryClient() - await queryClient.prefetchQuery({ + queryClient.prefetchQuery({ queryKey: key, - queryFn: () => Promise.resolve('hydrated'), + queryFn: () => sleep(10).then(() => 'hydrated'), }) + await vi.advanceTimersByTimeAsync(10) const persister = createMockPersister() - await persistQueryClientSave({ queryClient, persister }) + persistQueryClientSave({ queryClient, persister }) + await vi.advanceTimersByTimeAsync(0) queryClient.clear() const onSuccess = vi.fn() - const queryFn1 = vi.fn().mockImplementation(async () => { - await sleep(10) - return 'queryFn1' - }) - const queryFn2 = vi.fn().mockImplementation(async () => { - await sleep(10) - return 'queryFn2' - }) + const queryFn1 = vi + .fn() + .mockImplementation(() => sleep(10).then(() => 'queryFn1')) + const queryFn2 = vi + .fn() + .mockImplementation(() => sleep(10).then(() => 'queryFn2')) function App() { const [client, setClient] = React.useState( @@ -659,8 +680,10 @@ describe('PersistQueryClientProvider', () => { const rendered = render() - await waitFor(() => rendered.getByText('hydrated')) - await waitFor(() => rendered.getByText('queryFn2')) + await act(() => vi.advanceTimersByTimeAsync(10)) + expect(rendered.getByText('hydrated')).toBeInTheDocument() + await act(() => vi.advanceTimersByTimeAsync(11)) + expect(rendered.getByText('queryFn2')).toBeInTheDocument() expect(queryFn1).toHaveBeenCalledTimes(0) expect(queryFn2).toHaveBeenCalledTimes(1) @@ -710,8 +733,7 @@ describe('PersistQueryClientProvider', () => { }, async restoreClient() { restoreCount++ - await sleep(10) - return storedState + return sleep(10).then(() => storedState) }, removeClient() { storedState = undefined @@ -722,26 +744,25 @@ describe('PersistQueryClientProvider', () => { const key = queryKey() const queryClient = new QueryClient() - await queryClient.prefetchQuery({ + queryClient.prefetchQuery({ queryKey: key, - queryFn: () => Promise.resolve('hydrated'), + queryFn: () => sleep(10).then(() => 'hydrated'), }) + await vi.advanceTimersByTimeAsync(10) const persister = createPersister() const onSuccess = vi.fn() - await persistQueryClientSave({ queryClient, persister }) + persistQueryClientSave({ queryClient, persister }) + await vi.advanceTimersByTimeAsync(0) queryClient.clear() function Page() { const state = useQuery({ queryKey: key, - queryFn: async () => { - await sleep(10) - return 'fetched' - }, + queryFn: () => sleep(10).then(() => 'fetched'), }) return ( @@ -764,9 +785,11 @@ describe('PersistQueryClientProvider', () => { , ) - await waitFor(() => rendered.getByText('fetchStatus: idle')) - await waitFor(() => rendered.getByText('hydrated')) - await waitFor(() => rendered.getByText('fetched')) + expect(rendered.getByText('fetchStatus: idle')).toBeInTheDocument() + await act(() => vi.advanceTimersByTimeAsync(10)) + expect(rendered.getByText('hydrated')).toBeInTheDocument() + await act(() => vi.advanceTimersByTimeAsync(11)) + expect(rendered.getByText('fetched')).toBeInTheDocument() expect(onSuccess).toHaveBeenCalledTimes(1) expect(restoreCount).toBe(1)