Тестирование в React часто требует понимания двух фундаментальных уровней: тестирование DOM и тестирование компонентов. Эти уровни различаются по целям, методам и подходам, и игнорирование этого различия может привести к созданию ненадежных или избыточных тестов.
Тестирование DOM ориентировано на взаимодействие пользователя с интерфейсом. Основная идея заключается в том, что тест проверяет, что видит и с чем взаимодействует пользователь, а не внутреннюю реализацию компонента.
Ключевые характеристики:
getByText, getByRole,
getByLabelText, queryByTestId).Пример теста DOM:
import { render, screen, fireEvent } from '@testing-library/react';
import Counter from './Counter';
test('увеличивает счетчик при клике на кнопку', () => {
render(<Counter />);
const button = screen.getByRole('button', { name: /увеличить/i });
fireEvent.click(button);
expect(screen.getByText(/текущее значение: 1/i)).toBeInTheDocument();
});
В этом примере тест ориентирован на результат для пользователя — отображение нового значения счетчика. Не важно, как устроено состояние внутри компонента.
Тестирование компонентов сосредоточено на внутренней логике и поведении компонента. Этот подход проверяет конкретные функции, состояние и взаимодействие между компонентами, включая props и вызовы функций.
Ключевые характеристики:
jest.fn() для проверки
колбеков и моков.Пример теста компонента:
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Button from './Button';
test('вызывает переданный onClick при клике', async () => {
const handleClick = jest.fn();
render(<Button onCl ick={handleClick}>Нажми меня</Button>);
const button = screen.getByRole('button', { name: /нажми меня/i });
await userEvent.click(button);
expect(handleClick).toHaveBeenCalledTimes(1);
});
Тест проверяет взаимодействие с props, а не визуальное отображение. Это важно для компонентов с логикой, которая влияет на состояние приложения, но может быть невидимой пользователю напрямую.
| Критерий | Тестирование DOM | Тестирование компонентов |
|---|---|---|
| Фокус | Пользовательский интерфейс | Внутренняя логика компонента |
| Методы поиска | getByText, getByRole |
getByTestId, прямой доступ к props |
| Устойчивость к изменениям | Высокая | Зависит от структуры компонента |
| Использование моков | Редко | Часто, для проверки колбеков и API |
| Цель | Проверка результата рендеринга | Проверка правильной работы логики |
Иногда полезно объединять оба уровня, чтобы тестировать и визуальный результат, и вызовы функций:
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Form from './Form';
test('отправляет данные формы и показывает сообщение', async () => {
const handleSubmit = jest.fn();
render(<Form onSub mit={handleSubmit} />);
await userEvent.type(screen.getByLabelText(/имя/i), 'Иван');
await userEvent.click(screen.getByRole('button', { name: /отправить/i }));
expect(handleSubmit).toHaveBeenCalledWith({ name: 'Иван' });
expect(screen.getByText(/форма отправлена/i)).toBeInTheDocument();
});
Здесь тест проверяет взаимодействие пользователя через DOM и вызов логики через props, что обеспечивает полный охват поведения компонента.
Разделение тестирования DOM и компонентов обеспечивает устойчивость тестов, легкость поддержки и ясное понимание целей каждого теста. Это фундаментальная практика для создания надежного и масштабируемого тестового покрытия в React-проектах.