diff --git a/packages/query-core/src/tests/queryCache.test.tsx b/packages/query-core/src/tests/queryCache.test.tsx index 3707856ed2..1cacf9896d 100644 --- a/packages/query-core/src/tests/queryCache.test.tsx +++ b/packages/query-core/src/tests/queryCache.test.tsx @@ -1,7 +1,8 @@ import { sleep, queryKey, createQueryClient } from './utils' import type { QueryClient } from '..' -import { QueryCache } from '..' +import { QueryCache, QueryObserver } from '..' import type { Query } from '.././query' +import { waitFor } from '@testing-library/react' describe('queryCache', () => { let queryClient: QueryClient @@ -37,6 +38,40 @@ describe('queryCache', () => { expect(callback).toHaveBeenCalled() }) + test('should notify query cache when a query becomes stale', async () => { + const key = queryKey() + const events: Array = [] + const unsubscribe = queryCache.subscribe((event) => { + events.push(event.type) + }) + + const observer = new QueryObserver(queryClient, { + queryKey: key, + queryFn: () => 'data', + staleTime: 10, + }) + + const unsubScribeObserver = observer.subscribe(jest.fn) + + await waitFor(() => { + expect(events.length).toBe(8) + }) + + expect(events).toEqual([ + 'added', // 1. Query added -> loading + 'observerResultsUpdated', // 2. Observer result updated -> loading + 'observerAdded', // 3. Observer added + 'observerResultsUpdated', // 4. Observer result updated -> fetching + 'updated', // 5. Query updated -> fetching + 'observerResultsUpdated', // 6. Observer result updated -> success + 'updated', // 7. Query updated -> success + 'observerResultsUpdated', // 8. Observer result updated -> stale + ]) + + unsubscribe() + unsubScribeObserver() + }) + test('should include the queryCache and query when notifying listeners', async () => { const key = queryKey() const callback = jest.fn() diff --git a/packages/react-query/src/__tests__/useQuery.test.tsx b/packages/react-query/src/__tests__/useQuery.test.tsx index e0e4cc1015..6667f16139 100644 --- a/packages/react-query/src/__tests__/useQuery.test.tsx +++ b/packages/react-query/src/__tests__/useQuery.test.tsx @@ -1022,24 +1022,32 @@ describe('useQuery', () => { states.push(state) - const { refetch } = state + return ( +
+
{state?.data}
+ +
+ ) + } - React.useEffect(() => { - setActTimeout(() => { - refetch() - }, 5) - }, [refetch]) + const rendered = renderWithClient(queryClient, ) - return null - } + await waitFor(() => { + rendered.getByText('test') + }) - renderWithClient(queryClient, ) + fireEvent.click(rendered.getByRole('button', { name: 'refetch' })) - await sleep(10) + await waitFor(() => { + rendered.getByText('test') + }) - expect(states.length).toBe(2) expect(states[0]).toMatchObject({ data: undefined }) expect(states[1]).toMatchObject({ data: 'test' }) + + // make sure no additional renders happen + await sleep(50) + expect(states.length).toBe(2) }) it('should throw an error when a selector throws', async () => { @@ -1602,18 +1610,21 @@ describe('useQuery', () => { states.push(state) - React.useEffect(() => { - setActTimeout(() => { - setCount(1) - }, 20) - }, []) - - return null + return ( +
+
data: {state.data}
+ +
+ ) } - renderWithClient(queryClient, ) + const rendered = renderWithClient(queryClient, ) + + await waitFor(() => rendered.getByText('data: 0')) + + fireEvent.click(rendered.getByRole('button', { name: 'setCount' })) - await waitFor(() => expect(states.length).toBe(5)) + await waitFor(() => rendered.getByText('data: 1')) // Initial expect(states[0]).toMatchObject({ @@ -1636,15 +1647,8 @@ describe('useQuery', () => { isSuccess: true, isPreviousData: true, }) - // Hook state update - expect(states[3]).toMatchObject({ - data: 0, - isFetching: true, - isSuccess: true, - isPreviousData: true, - }) // New data - expect(states[4]).toMatchObject({ + expect(states[3]).toMatchObject({ data: 1, isFetching: false, isSuccess: true, @@ -2202,38 +2206,6 @@ describe('useQuery', () => { expect(states[2]).toMatchObject({ isStale: true }) }) - it('should notify query cache when a query becomes stale', async () => { - const key = queryKey() - const states: UseQueryResult[] = [] - const fn = jest.fn() - - const unsubscribe = queryCache.subscribe(fn) - - function Page() { - const state = useQuery(key, () => 'test', { - staleTime: 10, - }) - states.push(state) - return null - } - - renderWithClient(queryClient, ) - - await sleep(20) - unsubscribe() - - // 1. Query added -> loading - // 2. Observer result updated -> loading - // 3. Observer added - // 4. Query updated -> success - // 5. Observer result updated -> success - // 6. Query updated -> stale - // 7. Observer options updated - // 8. Observer result updated -> stale - // 9. Observer options updated - expect(fn).toHaveBeenCalledTimes(9) - }) - it('should not re-render when it should only re-render on data changes and the data did not change', async () => { const key = queryKey() const states: UseQueryResult[] = [] @@ -3821,18 +3793,35 @@ describe('useQuery', () => { results.push(result) - React.useEffect(() => { - setActTimeout(() => { - setShouldFetch(false) - }, 5) - }, []) - - return null + return ( +
+
{result.data}
+
{shouldFetch ? 'enabled' : 'disabled'}
+ +
+ ) } - renderWithClient(queryClient, ) + const rendered = renderWithClient(queryClient, ) + + await waitFor(() => { + rendered.getByText('fetched data') + rendered.getByText('enabled') + }) + + fireEvent.click(rendered.getByRole('button', { name: /enable/i })) + + await waitFor(() => { + rendered.getByText('fetched data') + rendered.getByText('disabled') + }) - await sleep(50) expect(results.length).toBe(3) expect(results[0]).toMatchObject({ data: 'initial', isStale: true }) expect(results[1]).toMatchObject({ data: 'fetched data', isStale: true }) diff --git a/packages/solid-query/src/__tests__/createQuery.test.tsx b/packages/solid-query/src/__tests__/createQuery.test.tsx index 6509af7eef..7f4217501b 100644 --- a/packages/solid-query/src/__tests__/createQuery.test.tsx +++ b/packages/solid-query/src/__tests__/createQuery.test.tsx @@ -2424,46 +2424,6 @@ describe('createQuery', () => { expect(states[2]).toMatchObject({ isStale: true }) }) - it('should notify query cache when a query becomes stale', async () => { - const key = queryKey() - const states: CreateQueryResult[] = [] - const fn = jest.fn() - - const unsubscribe = queryCache.subscribe(fn) - - function Page() { - const state = createQuery(key, () => 'test', { - staleTime: 10, - }) - createRenderEffect(() => { - states.push({ ...state }) - }) - return null - } - - render(() => ( - - - - )) - - await sleep(20) - unsubscribe() - - // 1. Query added -> loading - // 2. Observer result updated -> loading - // 3. Observer added - // 4. Query updated -> success - // 5. Observer result updated -> success - // 6. Query updated -> stale - // 7. Observer options updated - // 8. Observer result updated -> stale - // 9. Observer options updated - // Number 9 wont run in Solid JS - // Number 9 runs in react because the component re-renders after 8 - expect(fn).toHaveBeenCalledTimes(8) - }) - it('should not re-render when it should only re-render on data changes and the data did not change', async () => { const key = queryKey() const states: CreateQueryResult[] = []