skip to Main Content

*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


  1. Chosen as BEST ANSWER

    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.

    beforeEach(() => {
      vi.useRealTimers()
    })
    afterEach(() => {
      vi.useFakeTimers()
    })
    

  2. 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search