*The gist has Stories, Tests, and Feature Code: https://gist.github.com/johntimothybailey/6aba19f4abb34d89b626e9fe906c5453
*
How do I write a Testing Library test for a component that uses Tanstack Query?
When I try the following the tests timeout. What I notice is that the isLoading
remains true
and the data
remains undefined
Originally, I discovered the issue when using MSW + Testing Library + Tanstack Query
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { screen, render, waitFor } from '@testing-library/react'
import { PropsWithChildren } from 'react'
import { expect, describe, it } from 'vitest'
import { Example } from './Example'
const queryClient = new QueryClient({
defaultOptions: {
queries: {
cacheTime: 0,
staleTime: 0,
retry: false,
},
},
})
const AllTheProviders = ({ children }: PropsWithChildren) => {
return (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
)
}
describe('Example', () => {
it('Load Complete', async () => {
render(<Example scenario="success" />, { wrapper: AllTheProviders })
expect(screen.queryByText('Loading')).toBeInTheDocument()
await waitFor(() => {
expect(screen.queryByText('Loading')).not.toBeInTheDocument()
expect(screen.queryByText('todo-1')).toBeInTheDocument()
})
})
it('Is Loading', async () => {
render(<Example scenario="success" />, { wrapper: AllTheProviders })
await waitFor(() => {
expect(screen.queryByLabelText('loading')).toBeInTheDocument()
expect(screen.queryByLabelText('todo-1')).not.toBeInTheDocument()
})
})
})
import { useQuery } from '@tanstack/react-query'
const awaitTimeout = (delay: number) =>
new Promise((resolve) => setTimeout(resolve, delay))
export const Example = ({ scenario }: { scenario: 'loading' | 'success' }) => {
const query = useQuery({
queryKey: ['example', scenario],
queryFn: async (data) => {
if (data.queryKey.includes('loading')) {
return awaitTimeout(1000)
}
await awaitTimeout(200)
return {
userId: 1,
id: 1,
title: 'todo-1',
completed: false,
}
},
})
if (query.isLoading) {
return <div>Loading</div>
}
if (query.isError) {
return <div aria-label="error">Error</div>
}
if (query.isSuccess && query.data) {
return <div aria-label="todo-1">{query.data?.title}</div>
}
return <div aria-label="unknown">Unknown Issue</div>
}
RESULT
vitest --run Example.test.tsx
Error: Test timed out in 5000ms.
If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".
at Timeout.<anonymous> (file:///Users/johnbailey/Development/Tryyb/spacedock/node_modules/.pnpm/@[email protected]/node_modules/@vitest/runner/dist/index.js:62:16)
at listOnTimeout (node:internal/timers:564:17)
at processTimers (node:internal/timers:507:7)
2
Answers
It turns out there was a test setup preventing the code to resolve.
I cannot modify and remove the setup scripts so I simply added the following to the describe of the tests.
Ah, I misread about MSW. The answer is you’re using the wrong matcher.
*ByLabelText
matchers actually look for inputs associated with the label. You don’t have any inputs associated with the label.In short, use a different matcher – like
*ByText
or*ByTestId