Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як тестувати компоненти, яким потрібні контекст, роутер чи інші провайдери?

Реальні компоненти рідко живуть самі по собі: вони читають тему, поточного користувача, маршрут, клієнт запитів. Без провайдерів у тесті вони падають або поводяться не так, як у застосунку.

Найпростіше - wrapper у render:

render(<Header />, {
  wrapper: ({ children }) => <AuthContext value={{ user: testUser, logout: vi.fn() }}>{children}</AuthContext>,
});

Для всього проєкту - власна функція render, яка обгортає компонент усім потрібним і дає змогу налаштувати кожен провайдер:

// src/test/render.tsx
import { render, type RenderOptions } from '@testing-library/react';
import { MemoryRouter } from 'react-router';

type Options = RenderOptions & { user?: User | null; route?: string };

export function renderWithProviders(ui: ReactElement, { user = null, route = '/', ...options }: Options = {}) {
  const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });

  function Providers({ children }: { children: ReactNode }) {
    return (
      <QueryClientProvider client={queryClient}>
        <AuthContext value={{ user, logout: vi.fn() }}>
          <MemoryRouter initialEntries={[route]}>{children}</MemoryRouter>
        </AuthContext>
      </QueryClientProvider>
    );
  }

  return render(ui, { wrapper: Providers, ...options });
}

export * from '@testing-library/react';
import { renderWithProviders, screen } from '../test/render';

test('гість бачить кнопку входу', () => {
  renderWithProviders(<Header />, { user: null });
  expect(screen.getByRole('link', { name: 'Увійти' })).toBeInTheDocument();
});

Що варто врахувати:

  • свіжий стан на кожен тест: клієнт запитів, сховище (Zustand, Redux) створюються всередині функції, а не на рівні модуля - інакше кеш з одного тесту впливає на інший;
  • retry: false для TanStack Query - інакше тест помилки чекатиме повторних спроб;
  • маршрутизатор у пам'яті (MemoryRouter, createMemoryRouter) - без реального URL браузера; початковий маршрут задається параметром;
  • підміняти лише те, що поза межами тесту: справжній контекст з тестовими даними краще за мок useContext - тест перевіряє реальну інтеграцію;
  • перевірка поведінки при різному контексті (гість / адміністратор / інша мова) стає одним параметром.

renderHook приймає той самий wrapper - хуки тестуються з тими самими провайдерами.

Докладніше в документації: React Testing Library: власний render

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання