Тестирование пользовательских взаимодействий (UI-тестирование) является неотъемлемой частью разработки приложений, особенно в современных веб-приложениях, где важную роль играют динамичные элементы интерфейса. В этой главе рассматривается, как с помощью Jest можно эффективно тестировать взаимодействие пользователя с интерфейсом, выявлять потенциальные ошибки и обеспечивать корректную работу всех элементов.
Тестирование пользовательских взаимодействий ориентировано на проверку того, как приложение реагирует на действия пользователя. Это включает в себя:
Цель такого тестирования — не только удостовериться в корректности работы интерфейса, но и в том, как приложение обрабатывает поведение пользователя в реальных условиях. Jest в связке с дополнительными инструментами, такими как Testing Library, предоставляет возможности для написания эффективных и надежных тестов для проверки пользовательских сценариев.
Jest — это фреймворк для юнит-тестирования, но для тестирования UI-взаимодействий требуется интеграция с другими библиотеками, такими как React Testing Library и user-event. React Testing Library помогает работать с компонентами в контексте DOM, в то время как user-event позволяет моделировать пользовательские действия, такие как клик мыши, ввод текста и другие взаимодействия.
Для написания тестов пользовательских взаимодействий необходимо комбинировать эти инструменты с Jest для проверки логики и корректности рендеринга компонентов.
Для начала необходимо отрендерить компонент, который будет подвергаться тестированию. Используя React Testing Library, можно сделать это следующим образом:
import { render, screen } from '@testing-library/react';
import UserForm from './UserForm';
test('форма рендерится корректно', () => {
render(<UserForm />);
const inputElement = screen.getByLabelText(/имя/i);
expect(inputElement).toBeInTheDocument();
});
Здесь происходит рендеринг компонента UserForm, после
чего с помощью screen.getByLabelText выбирается элемент
формы по метке (label). Важно использовать семантические методы выборки,
чтобы тесты оставались стабильными и не зависели от деталей
реализации.
После того как компонент рендерится, необходимо смоделировать действия пользователя. Для этого используется библиотека user-event.
Пример клика по кнопке:
import userEvent from '@testing-library/user-event';
test('кнопка отправки формы должна вызвать обработчик', async () => {
render(<UserForm />);
const submitButton = screen.getByRole('button', { name: /отправить/i });
userEvent.click(submitButton);
// Проверка, что форма была отправлена
expect(await screen.findByText(/форма отправлена/i)).toBeInTheDocument();
});
Здесь с помощью userEvent.click() эмулируется клик по
кнопке, а затем проверяется, что после клика отобразилось сообщение об
успешной отправке формы.
Когда необходимо протестировать, как компоненты реагируют на ввод
данных в поля формы, можно использовать функцию
userEvent.type():
test('пользователь может ввести имя в поле', async () => {
render(<UserForm />);
const inputElement = screen.getByLabelText(/имя/i);
await userEvent.type(inputElement, 'Иван');
expect(inputElement).toHaveValue('Иван');
});
В данном примере происходит ввод текста в поле с помощью метода
type, после чего проверяется, что значение в поле
изменилось.
Иногда требуется протестировать сложные сценарии, где взаимодействуют несколько элементов. Например, если пользователь сначала вводит данные в форму, а затем нажимает кнопку, чтобы отправить эти данные:
test('пользователь может отправить форму с данными', async () => {
render(<UserForm />);
const nameInput = screen.getByLabelText(/имя/i);
const submitButton = screen.getByRole('button', { name: /отправить/i });
await userEvent.type(nameInput, 'Иван');
userEvent.click(submitButton);
// Проверка, что форма была отправлена и данные отображаются
expect(await screen.findByText(/форма отправлена/i)).toBeInTheDocument();
expect(await screen.findByText(/Иван/i)).toBeInTheDocument();
});
Здесь тестируется сценарий, когда после ввода данных в форму и отправки, форма должна отобразить введенные данные.
Некоторые действия, такие как отправка формы, могут приводить к асинхронным операциям, например, запросам на сервер. В таких случаях важно использовать асинхронные методы для проверки изменений в DOM.
Jest предоставляет async/await синтаксис для работы с
асинхронными операциями:
test('форму можно отправить, и сервер вернет успешный ответ', async () => {
render(<UserForm />);
const inputElement = screen.getByLabelText(/имя/i);
const submitButton = screen.getByRole('button', { name: /отправить/i });
await userEvent.type(inputElement, 'Иван');
userEvent.click(submitButton);
// Проверка асинхронного состояния
const successMessage = await screen.findByText(/форма успешно отправлена/i);
expect(successMessage).toBeInTheDocument();
});
В данном примере после отправки формы проверяется, что отображается
сообщение об успешной отправке. Так как это может быть асинхронная
операция, используется await для ожидания появления текста
в DOM.
Часто компоненты взаимодействуют с внешними API или сервером. Для того чтобы тестировать такие компоненты, важно мокаить запросы, чтобы не зависеть от реальных серверов. Jest предоставляет встроенные функции для мока.
Пример мока API-запроса:
jest.mock('axios');
import axios from 'axios';
test('форма отправляет запрос на сервер', async () => {
axios.post.mockResolvedValue({ data: { message: 'Success' } });
render(<UserForm />);
const inputElement = screen.getByLabelText(/имя/i);
const submitButton = screen.getByRole('button', { name: /отправить/i });
await userEvent.type(inputElement, 'Иван');
userEvent.click(submitButton);
// Проверка, что запрос был отправлен
expect(axios.post).toHaveBeenCalledWith('/submit', { name: 'Иван' });
});
Здесь мы мокируем функцию axios.post и проверяем, что
она была вызвана с нужными параметрами.
getByLabelText, getByRole, а не
getByTestId).async/await и методов ожидания,
таких как findBy или waitFor.Правильно организованные тесты пользовательских взаимодействий повышают надежность приложений, минимизируя вероятность ошибок при взаимодействии с интерфейсом.