Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion packages/query-core/src/tests/queryCache.test.tsx
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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<string> = []
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()
Expand Down
127 changes: 58 additions & 69 deletions packages/react-query/src/__tests__/useQuery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1022,24 +1022,32 @@ describe('useQuery', () => {

states.push(state)

const { refetch } = state
return (
<div>
<div>{state?.data}</div>
<button onClick={() => state.refetch()}>refetch</button>
</div>
)
}

React.useEffect(() => {
setActTimeout(() => {
refetch()
}, 5)
}, [refetch])
const rendered = renderWithClient(queryClient, <Page />)

return null
}
await waitFor(() => {
rendered.getByText('test')
})

renderWithClient(queryClient, <Page />)
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 () => {
Expand Down Expand Up @@ -1602,18 +1610,21 @@ describe('useQuery', () => {

states.push(state)

React.useEffect(() => {
setActTimeout(() => {
setCount(1)
}, 20)
}, [])

return null
return (
<div>
<div>data: {state.data}</div>
<button onClick={() => setCount(1)}>setCount</button>
</div>
)
}

renderWithClient(queryClient, <Page />)
const rendered = renderWithClient(queryClient, <Page />)

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({
Expand All @@ -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,
Expand Down Expand Up @@ -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<string>[] = []
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, <Page />)

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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the comments about the "9 updates" is still here, but the assertion is gone 🤔

I also don't know what the states.push are actually doing here. Nothing it seems.

I think this is one of the tests that should actually live in the query-core, not react-query. There is no nothing react specific about should notify query cache when a query becomes stale

we could do:

  • subscribe to queryCache
  • create an observer with a staleTime
  • do the same checks there ...

this would also get rid of the test duplication in solidJs

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All right, I'll give that a try

})

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<string>[] = []
Expand Down Expand Up @@ -3821,18 +3793,35 @@ describe('useQuery', () => {

results.push(result)

React.useEffect(() => {
setActTimeout(() => {
setShouldFetch(false)
}, 5)
}, [])

return null
return (
<div>
<div>{result.data}</div>
<div>{shouldFetch ? 'enabled' : 'disabled'}</div>
<button
onClick={() => {
setShouldFetch(false)
}}
>
enable
</button>
</div>
)
}

renderWithClient(queryClient, <Page />)
const rendered = renderWithClient(queryClient, <Page />)

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 })
Expand Down
40 changes: 0 additions & 40 deletions packages/solid-query/src/__tests__/createQuery.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>[] = []
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(() => (
<QueryClientProvider client={queryClient}>
<Page />
</QueryClientProvider>
))

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<string>[] = []
Expand Down