User-centric testing в контексте React Testing Library (RTL) основывается на ключевой идее: тестирование должно фокусироваться на том, как пользователь взаимодействует с интерфейсом, а не на внутренней реализации компонентов. Этот подход отличается от традиционного unit-тестирования, где проверяются методы и свойства компонентов, часто завязанные на структуру DOM.
1. Проверка поведения, а не структуры RTL поощряет
использование методов, которые имитируют пользовательские действия:
клики, ввод текста, выбор элементов из выпадающих списков. Вместо того
чтобы тестировать наличие <div> с определённым
классом, важно проверить, что пользователь видит ожидаемый
результат.
Пример:
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import MyForm from './MyForm';
test('отправка формы показывает сообщение об успехе', async () => {
render(<MyForm />);
await userEvent.type(screen.getByLabelText(/имя/i), 'Иван');
await userEvent.click(screen.getByRole('button', { name: /отправить/i }));
expect(screen.getByText(/успешно отправлено/i)).toBeInTheDocument();
});
Здесь тест проверяет результат действий пользователя, а не внутренние состояния компонента.
2. Поиск элементов через их семантику RTL предлагает четыре основных способа поиска элементов:
getBy… – для уверенного нахождения элемента,
выбрасывает ошибку, если элемент не найден.queryBy… – возвращает null, если элемент
отсутствует, что удобно для отрицательных проверок.findBy… – возвращает промис и используется для
асинхронного поиска.allBy… – для поиска всех элементов, соответствующих
критериям.Основная рекомендация: использовать поиск через роли
(getByRole) или текст (getByText),
поскольку это повторяет реальные сценарии использования интерфейса.
Пример использования ролей:
const button = screen.getByRole('button', { name: /сохранить/i });
Этот подход гарантирует, что тест останется валидным даже при изменении структуры HTML, если функциональность останется прежней.
3. Асинхронное поведение и ожидания В современных приложениях интерфейс часто обновляется асинхронно: загрузка данных, отправка формы, анимации. RTL предоставляет удобные инструменты для ожидания этих изменений:
findBy… с awaitwaitFor для проверки состояния после задержкиwaitForElementToBeRemoved для ожидания исчезновения
элементаПример:
import { waitFor } from '@testing-library/react';
await waitFor(() => {
expect(screen.getByText(/данные загружены/i)).toBeInTheDocument();
});
Эти методы предотвращают нестабильность тестов, делая их более надёжными.
4. Моделирование действий пользователя RTL
использует библиотеку user-event для имитации действий
пользователя. Это более реалистично, чем прямое изменение значений через
fireEvent, поскольку userEvent учитывает
задержки, фокус и порядок событий.
Примеры действий:
userEvent.click(element) — имитация кликаuserEvent.type(input, 'текст') — ввод текстаuserEvent.selectOptions(select, 'option') — выбор из
спискаuserEvent.hover(element) — наведение курсораЭти методы создают тесты, максимально приближенные к реальному использованию приложения.
5. Минимизация зависимости от реализации Тесты, завязанные на конкретной структуре DOM или внутренних методах, становятся хрупкими. User-centric подход советует:
6. Комбинирование с Jest и снапшотами Хотя основной фокус — действия пользователя, user-centric тестирование часто дополняется проверками состояния компонента через Jest:
jest.fn()) при
взаимодействии с UI.Пример проверки вызова функции:
const handleSubmit = jest.fn();
render(<MyForm onSub mit={handleSubmit} />);
await userEvent.click(screen.getByRole('button', { name: /отправить/i }));
expect(handleSubmit).toHaveBeenCalledTimes(1);
7. Принцип «тест как история пользователя» Каждый тест должен быть мини-сценарием взаимодействия пользователя. Структура типичного теста:
render(<Component />))getByRole,
getByLabelText)userEvent.click,
userEvent.type)expect(...).toBeInTheDocument())Такой подход делает тесты читаемыми, устойчивыми к изменениям кода и ближе к реальному поведению приложения.
User-centric testing в React Testing Library превращает тесты из проверки кода в проверку опыта пользователя, делая их надежными, понятными и полезными для долгосрочной поддержки проекта.