События и их симуляция

В тестировании JavaScript-приложений важной частью является проверка взаимодействия компонентов с пользователем. Одним из таких взаимодействий являются события, которые могут происходить в различных частях пользовательского интерфейса: клики по кнопкам, ввод текста в форму, перемещение мыши и другие действия. В Jest для работы с событиями используется функционал, позволяющий не только отслеживать их, но и симулировать, имитируя реальные пользовательские действия.

Основы событий в JavaScript

События в JavaScript — это сигналы, которые генерируются браузером или пользователем для выполнения определённого действия в приложении. Эти события могут быть связаны с различными действиями, такими как:

  • Мышь: клик, нажатие и отпускание кнопки мыши, перемещение мыши.
  • Клавиатура: нажатие клавиш.
  • Формы: отправка формы, изменение значений в полях ввода.
  • Другие: фокусировка, изменение состояния элементов, скроллинг и другие.

События обрабатываются через обработчики событий, которые могут быть привязаны к элементам DOM. Для их проверки в тестах важно правильно смоделировать эти события, чтобы убедиться, что приложение правильно реагирует на действия пользователя.

Модуль @testing-library/react и симуляция событий

Jest часто используется вместе с библиотекой @testing-library/react, которая предоставляет удобные инструменты для тестирования React-компонентов. Одним из таких инструментов является симуляция событий, позволяющая эмулировать действия пользователя и проверять поведение компонентов в ответ на них.

В @testing-library/react для симуляции событий используется функция fireEvent, которая позволяет отправлять различные события на элементы. Она поддерживает все основные типы событий, такие как click, change, input, submit и другие.

Пример использования fireEvent

Для начала рассмотрим простой пример, где мы создаём кнопку, которая изменяет текст при клике:

import { render, fireEvent } from '@testing-library/react';
import MyComponent from './MyComponent';

test('изменяет текст при клике', () => {
  const { getByText } = render(<MyComponent />);

  const button = getByText('Нажми меня');
  fireEvent.click(button);

  const updatedText = getByText('Текст изменён');
  expect(updatedText).toBeInTheDocument();
});

В этом примере мы:

  1. Рендерим компонент MyComponent.
  2. Находим кнопку с текстом “Нажми меня”.
  3. Симулируем клик по кнопке с помощью fireEvent.click.
  4. Проверяем, что текст компонента изменился на “Текст изменён”.

Типы событий и их симуляция

fireEvent поддерживает множество типов событий, и каждый из них используется для разных целей. Рассмотрим наиболее распространённые:

Клик по элементу (click)

Для симуляции клика по элементу используется метод fireEvent.click. Этот метод используется для проверки, что обработчик события, привязанный к элементу, срабатывает корректно.

fireEvent.click(button);

Ввод текста в поле (change, input)

Когда пользователь вводит текст в форму, мы можем симулировать это событие с помощью fireEvent.change или fireEvent.input. Оба события связаны с изменением значения в элементах формы, но между ними есть различия в поведении.

  • change — срабатывает, когда значение поля изменилось и фокус с поля был потерян (например, когда пользователь выходит из поля ввода).
  • input — срабатывает при каждом изменении значения поля (обычно используется для отслеживания ввода текста).

Пример симуляции ввода текста:

const input = getByLabelText('Имя');
fireEvent.change(input, { target: { value: 'Иван' } });

expect(input.value).toBe('Иван');

Отправка формы (submit)

Для симуляции отправки формы используется событие submit. Это событие полезно, чтобы проверить, что форма правильно обрабатывает отправку данных.

const form = getByTestId('my-form');
fireEvent.submit(form);

Фокусировка и размытие (focus, blur)

Интерактивность с элементами формы может включать фокусировку и размытие (потерю фокуса). Для этих случаев можно использовать события focus и blur.

const input = getByLabelText('Имя');
fireEvent.focus(input);
fireEvent.blur(input);

Проверка асинхронных действий

Симуляция событий в сочетании с асинхронными действиями, такими как загрузка данных с сервера или обработка отложенных функций, требует правильной организации тестов. Jest и @testing-library/react предоставляют функции, которые позволяют работать с асинхронными событиями.

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

import { waitFor } from '@testing-library/react';

test('загружает данные при клике', async () => {
  const { getByText } = render(<MyComponent />);

  const button = getByText('Загрузить данные');
  fireEvent.click(button);

  await waitFor(() => expect(getByText('Данные загружены')).toBeInTheDocument());
});

Здесь мы симулируем клик по кнопке, инициирующий асинхронную операцию, и ожидаем появления текста “Данные загружены”, что указывает на успешное завершение операции.

Симуляция событий с использованием пользовательских событий

Иногда в тестах возникает необходимость симулировать более сложные события, например, пользовательские. Для этого можно использовать конструктор Event, чтобы создать событие и передать его в элемент.

const event = new Event('myCustomEvent');
fireEvent(element, event);

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

Использование user-event для более реалистичных симуляций

Библиотека @testing-library/user-event предоставляет более высокоуровневые функции для симуляции пользовательских действий, таких как ввод текста, клик, фокусировка и другие. Это более гибкий инструмент, который лучше эмулирует поведение реальных пользователей по сравнению с fireEvent.

Пример использования user-event для ввода текста:

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

const input = getByLabelText('Имя');
userEvent.type(input, 'Иван');

expect(input.value).toBe('Иван');

Мокирование событий

В некоторых случаях тесты могут требовать мокирования (подмены) событий для проверки работы системы в специфических условиях. Jest предоставляет удобные средства для мокирования функций, включая обработчики событий. Это особенно полезно при тестировании компонентов, которые реагируют на события в контексте взаимодействия с внешними системами или при проверке ошибок.

const mockHandler = jest.fn();
fireEvent.click(button);
expect(mockHandler).toHaveBeenCalled();

Заключение

Симуляция событий в Jest — это мощный инструмент для тестирования поведения интерфейса. Благодаря библиотекам @testing-library/react и @testing-library/user-event, тестирование пользовательских действий стало проще и более эффективным. Правильная симуляция событий позволяет глубже тестировать компоненты и улучшить качество программного обеспечения, обеспечивая уверенность в том, что приложение правильно реагирует на действия пользователя.