Импорт и конфигурация userEvent

userEvent — это утилита для симуляции действий пользователя в тестах на React, предоставляемая пакетом @testing-library/user-event. Она расширяет возможности стандартного fireEvent, предоставляя более реалистичное поведение: клики, ввод текста, наведение мыши, выбор элементов и другие пользовательские взаимодействия.

Установка и импорт

Для работы с userEvent необходимо установить соответствующий пакет:

npm install --save-dev @testing-library/user-event

Импортировать модуль следует следующим образом:

import userEvent from '@testing-library/user-event';

В последних версиях пакета userEvent создается как объект с методами через фабрику, что позволяет конфигурировать его поведение:

const user = userEvent.setup();

Использование setup() важно, так как оно поддерживает асинхронные действия и позволяет задавать глобальные настройки, например, задержку между действиями, моделируя реальные пользовательские события.

Настройка userEvent

userEvent.setup() принимает объект с опциями конфигурации. Основные параметры:

  • delay — время задержки между симулируемыми событиями, полезно для тестирования пользовательских ожиданий и анимаций.

    const user = userEvent.setup({ delay: 100 });

    Здесь ввод текста или клики будут происходить с задержкой 100 миллисекунд между событиями.

  • pointerEventsCheck — включает проверку событий указателя. По умолчанию true, что предотвращает выполнение событий на неактивных или скрытых элементах.

  • keyboardMap — позволяет задать собственную раскладку клавиатуры, если требуется тестировать ввод с нестандартной локалью или специальные символы.

  • advanceTimers — функция для контроля таймеров при использовании jest.useFakeTimers() или аналогичных инструментов. Позволяет корректно симулировать асинхронные действия.

Пример комплексной настройки:

const user = userEvent.setup({
  delay: 50,
  pointerEventsCheck: true,
  advanceTimers: jest.advanceTimersByTime
});

Применение userEvent в тестах

Методы userEvent полностью асинхронны и требуют использования await при взаимодействии с элементами:

import { render, screen } from '@testing-library/react';
import MyForm from './MyForm';

test('пользователь вводит текст и отправляет форму', async () => {
  const user = userEvent.setup();
  render(<MyForm />);

  const input = screen.getByLabelText(/имя/i);
  const button = screen.getByRole('button', { name: /отправить/i });

  await user.type(input, 'Иван');
  await user.click(button);

  expect(screen.getByText(/Спасибо, Иван!/i)).toBeInTheDocument();
});

Особенности:

  • user.type(element, text) имитирует ввод текста, вызывая события keydown, keypress, input, keyup.
  • user.click(element) вызывает последовательность событий mousedown, mouseup, click.
  • user.hover(element) и user.unhover(element) позволяют тестировать реакции на наведение мыши.
  • Методы можно комбинировать и вызывать последовательно, что позволяет создавать сценарии, максимально приближенные к реальному поведению пользователя.

Различие между userEvent и fireEvent

fireEvent просто генерирует одно событие на элементе:

fireEvent.click(button);

userEvent симулирует полный цикл действий пользователя, включая все промежуточные события и состояние браузера:

await user.click(button);

Преимущества:

  • Более реалистичное тестирование пользовательского взаимодействия.
  • Поддержка асинхронного поведения и задержек.
  • Простая интеграция с таймерами и анимациями.

Асинхронные сценарии

Так как современные интерфейсы часто используют асинхронные обновления состояния, userEvent обеспечивает корректное выполнение цепочек событий. Любой метод возвращает промис, который можно await:

await user.type(input, 'Тест');
await user.click(submitButton);

Это гарантирует, что состояние компонента будет актуальным после каждого действия, и тест не упадет из-за несинхронных обновлений.

Интеграция с React Testing Library

userEvent идеально сочетается с screen и render, предоставляя единый инструмент для:

  • Поиска элементов (getByRole, getByLabelText, getByText).
  • Асинхронного взаимодействия.
  • Проверки состояния DOM после действий пользователя.

Практические рекомендации

  1. Всегда использовать await для всех методов userEvent.
  2. Для сложных сценариев создавать отдельный объект user = userEvent.setup() с конфигурацией.
  3. Предпочитать userEvent вместо fireEvent, если необходимо имитировать реальные действия пользователя.
  4. Использовать delay только при необходимости моделирования реального ввода, чтобы не замедлять тесты без причины.
  5. Проверять поведение скрытых или отключенных элементов с помощью pointerEventsCheck, чтобы избежать ложноположительных результатов.

Использование userEvent позволяет создавать тесты, максимально приближенные к реальному поведению пользователя, и значительно повышает надежность проверок UI-компонентов в React.