Unit-тесты в React: практический пример для 2025
Практический гайд по unit-тестам в React: настройка Jest, работа с RTL и MSW, снимки и типичные ошибки.
Unit-тесты в React фиксируют ожидаемое поведение сразу после написания кода. Когда в проекте уже десятки компонентов, каждый скрытый баг превращается в большую головную боль, поэтому надежный набор тестов обязателен.
Иногда можно попробовать сначала отрефакторить код, чтобы упростить тестирование. Подробнее о рефакторинге в статье Рефакторинг кода в React 2025: практический подход.
1. Подготовка окружения: Jest + React Testing Library
Самый популярный стек остается актуальным: Jest тест-раннер, и React Testing Library (RTL) утилита для работы с DOM. Установить все одной командой:
npm i -D jest @testing-library/react @testing-library/jest-dom
Для TypeScript добавьте ts-jest
и создайте jest.config.js
:
module.exports = {
preset: "ts-jest",
testEnvironment: "jsdom",
setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"],
};
В jest.setup.ts
подключаем расширения RTL:
import "@testing-library/jest-dom";
Скрипт test:watch
дает быстрый отклик при изменениях.
2. Тестируем синхронный рендер компонента
Компонент UserCard
принимает пропсы и выводит имя. Тест проверяет появление текста.
import { render, screen } from "@testing-library/react";
import UserCard from "./UserCard";
test("отображает имя пользователя", () => {
render(<UserCard name="Иван" />);
expect(screen.getByText("Иван")).toBeInTheDocument();
});
- Не используем
container
напрямую RTL советует искать элементы так, как их ищет пользователь. toBeInTheDocument
делает проверку читаемой.- Уточняйте типы пропсов в TypeScript, чтобы избежать ошибок в рантайме.
3. Асинхронные запросы и мок-сервер
Компоненты, делающие запросы к API, часто становятся источником багов. В 2025 году рекомендуется Mock Service Worker (MSW) он перехватывает запросы на уровне сети и не требует правок кода.
// src/mocks/handlers.ts
import { rest } from "msw";
export const handlers = [
rest.get("/api/users", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json([
{ id: 1, name: "Алиса" },
{ id: 2, name: "Боб" },
])
);
}),
];
Запуск MSW в тестах:
// src/setupTests.ts
import { server } from "./mocks/server";
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Тестируем компонент UserList
:
import { render, screen, waitFor } from "@testing-library/react";
import UserList from "./UserList";
test("загружает и отображает список пользователей", async () => {
render(<UserList />);
expect(screen.getByText("Загрузка…")).toBeInTheDocument();
await waitFor(() => expect(screen.getByText("Алиса")).toBeInTheDocument());
expect(screen.getByText("Боб")).toBeInTheDocument();
});
4. Снимки состояния (snapshot) когда они уместны
Snapshot-тесты подходят только для “статических” компонентов без бизнес-логики.
import { render } from "@testing-library/react";
import Header from "./Header";
test("snapshot Header", () => {
const { asFragment } = render(<Header title="Главная" />);
expect(asFragment()).toMatchSnapshot();
});
Новые рекомендации 2025: с версии @testing-library/jest-dom
v6 рекомендуется задавать опцию ignoreAttributes: ['style']
в toMatchSnapshot
, чтобы избегать лишних срабатываний при изменении стилистики.
Плюсы: быстрый способ убедиться, что разметка не изменилась без намерения.
Минусы: ложные срабатывания при изменении небольших атрибутов. Храните такие тесты в папке __snapshots__
и запускать их периодически, а не на каждом CI-билде.
5. Таблица типичных ошибок и способы их устранения
Ошибка | Почему происходит | Как исправить |
---|---|---|
Тест падает из-за тайм-аутов | Асинхронный запрос не завершен | Добавьте await waitFor или используйте findBy* |
Мок-сервер не перехватывает запрос | Неправильный путь в rest.get | Проверьте URL, используйте * для wildcard |
Снимки постоянно меняются | Переход на новую версию UI-библиотеки | Пересмотрите необходимость snapshot-теста |
Тесты зависят от глобального состояния | Не очищаете localStorage /sessionStorage | Добавьте cleanup в afterEach |
Ожидание null вместо undefined | Неправильный тип пропса | Явно указывайте типы в TypeScript |
Эти подсказки помогут держать unit-тесты в React чистыми и быстрыми.
FAQ / чеклист
- Не путайте unit-тесты с e2e проверяйте лишь один компонент, а не весь пользовательский путь.
- Отдавайте предпочтение
findBy*
вместоwaitFor
, когда ждете появления элемента в DOM. - Храните мок-данные рядом с тестом, чтобы они не “засоряли” продакшн-код.
- Не пишите тесты на стили проверяйте только семантику (текст, роли, атрибуты).
- Регулярно обновляйте snapshots, но только после осознанного ревью изменений.
Unit-тесты в React остаются важным инструментом, позволяющим быстро обнаружить регрессии и поддерживать качество кода без лишних хлопот.