Dev Highlights

Доки по разработке

This project is maintained by teniryte

14. Тестирование и качество

TanStack Query легко тестируется, если вы делаете две вещи:

Базовый wrapper

import { QueryClient, QueryClientProvider } from '@tanstack/react-query'

export function createTestQueryClient() {
  return new QueryClient({
    defaultOptions: {
      queries: {
        retry: false,
      },
      mutations: {
        retry: false,
      },
    },
  })
}

export function createWrapper() {
  const queryClient = createTestQueryClient()

  return function Wrapper({ children }: { children: React.ReactNode }) {
    return (
      <QueryClientProvider client={queryClient}>
        {children}
      </QueryClientProvider>
    )
  }
}

Тест hook с renderHook

Для React 18+ используйте renderHook из @testing-library/react.

import { renderHook, waitFor } from '@testing-library/react'

test('loads todos', async () => {
  const wrapper = createWrapper()

  const { result } = renderHook(() => useTodos(), { wrapper })

  await waitFor(() => expect(result.current.isSuccess).toBe(true))
  expect(result.current.data).toEqual([{ id: '1', title: 'Learn Query' }])
})

Почему отключают retry

По умолчанию query ретраятся 3 раза. Это:

Поэтому retry: false в test client почти всегда разумный дефолт.

Jest и gcTime

Если вы явно меняете gcTime и используете Jest, иногда полезно держать gcTime: Infinity, чтобы избежать проблем с незавершёнными таймерами. В серверном окружении это и так значение по умолчанию.

Что тестировать

Имеет смысл тестировать:

Тестирование network layer

Подходы:

Главное правило: не мокайте TanStack Query, мокайте сеть или API-слой.

Тест infinite query

test('loads next page', async () => {
  const wrapper = createWrapper()

  const { result } = renderHook(() => useFeed(), { wrapper })

  await waitFor(() => expect(result.current.isSuccess).toBe(true))

  await result.current.fetchNextPage()

  await waitFor(() =>
    expect(result.current.data.pages).toHaveLength(2),
  )
})

Тест optimistic update

Проверяйте два сценария:

  1. optimistic state появился сразу
  2. rollback сработал при ошибке

Это особенно важно для финансовых, административных и collaborative экранов.

Практические рекомендации