React Testing Library (RTL) предоставляет два основных способа
симуляции действий пользователя: fireEvent
и userEvent. Они служат для тестирования
пользовательских интерфейсов, но имеют принципиальные различия в подходе
и уровне абстракции. Понимание этих различий критично для написания
корректных и реалистичных тестов.
fireEvent:
низкоуровневый подходfireEvent позволяет вручную инициировать события DOM,
такие как click, change, input,
submit. Он ближе к чистому DOM API и предоставляет прямой
доступ к событиям.
Пример использования fireEvent:
import { render, fireEvent, screen } from '@testing-library/react';
import MyForm from './MyForm';
test('изменение значения input с помощью fireEvent', () => {
render(<MyForm />);
const input = screen.getByLabelText('Имя');
fireEvent.change(input, { target: { value: 'Иван' } });
expect(input.value).toBe('Иван');
});
Особенности fireEvent:
userEvent:
высокоуровневая симуляцияuserEvent — это утилита, которая строится поверх
fireEvent, но имитирует реальное поведение
пользователя. Она учитывает последовательность событий,
задержки и дополнительные вызовы браузера, которые происходят при
настоящем взаимодействии.
Пример использования userEvent:
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import MyForm from './MyForm';
test('изменение значения input с помощью userEvent', async () => {
render(<MyForm />);
const input = screen.getByLabelText('Имя');
await userEvent.type(input, 'Иван');
expect(input.value).toBe('Иван');
});
Преимущества userEvent:
keydown → keypress → input →
keyup).fireEvent и userEvent| Характеристика | fireEvent | userEvent |
|---|---|---|
| Уровень абстракции | Низкий | Высокий |
| Реалистичность | Минимальная | Близка к реальному пользователю |
| Обработка цепочек событий | Нет | Да |
| Скорость выполнения | Высокая | Немного медленнее |
| Основное применение | Проверка отдельных событий | Проверка пользовательских сценариев |
| Асинхронность | Обычно синхронно | Часто асинхронно (например, userEvent.type) |
fireEventПример:
fireEvent.click(button);
expect(mockHandler).toHaveBeenCalledTimes(1);
userEventПример:
await userEvent.click(dropdownButton);
await userEvent.click(optionItem);
expect(screen.getByText('Выбранная опция')).toBeInTheDocument();
awaituserEvent часто возвращает промис, особенно при вводе
текста (type), что требует использования
async/await. Это позволяет корректно обрабатывать задержки
между событиями и обновления состояния компонентов.
await userEvent.type(input, 'Текст');
Использование await гарантирует, что все события
завершены перед проверкой результата.
fireEvent.userEvent.userEvent, так как он ближе к реальным
условиям работы приложения.fireEvent и userEvent дополняют друг друга:
первый — для точечных проверок событий, второй — для комплексного
тестирования поведения. Грамотное сочетание этих инструментов
обеспечивает надёжность и читаемость тестов.
userEvent становится стандартом для симуляции
пользовательских действий, особенно там, где важны естественные
взаимодействия с интерфейсом, а fireEvent остаётся
полезным для низкоуровневой отладки событий.