Create React App — это популярный инструмент для быстрого старта в разработке React-приложений. Он предоставляет базовую настройку для проекта, избавляя разработчика от необходимости конфигурировать различные сборщики, компиляторы и другие инструменты. Для тестирования React-компонентов в таких проектах часто используется React Testing Library (RTL). Эта библиотека ориентирована на поведение компонентов и помогает писать тесты, которые имитируют реальное взаимодействие с пользовательским интерфейсом. В контексте создания тестов с использованием RTL и Create React App, существует несколько особенностей, которые стоит учитывать.
После создания проекта с помощью npx create-react-app
тестовая среда уже настроена по умолчанию. Включение React
Testing Library происходит автоматически, так как Create React
App использует Jest как тестовый фреймворк, который интегрируется с
RTL.
Основная структура проекта будет включать папку src с
компонентами, и папку __tests__ (или тесты могут быть
расположены рядом с компонентами в отдельных файлах с расширением
.test.js).
Пример базовой структуры проекта:
/my-app
/node_modules
/public
/src
/components
MyComponent.js
MyComponent.test.js
/__tests__
/App.test.js
package.json
Тесты для компонентов помещаются в файлы с расширением
.test.js рядом с самими компонентами. Это помогает легче
поддерживать тесты, особенно когда проект растет.
React Testing Library делает акцент на том, чтобы тесты были максимально близки к тому, как компоненты работают в реальном браузере. RTL помогает писать тесты, используя такие принципы, как:
getByText, getByRole,
getByLabelText, которые имитируют взаимодействие с
DOM.Для проектов, созданных через create-react-app, не нужно
дополнительно устанавливать React Testing Library, так как она уже
входит в зависимости по умолчанию. Тем не менее, если по каким-то
причинам библиотека не установлена, можно добавить её вручную:
npm install --save @testing-library/react @testing-library/jest-dom
Для того чтобы протестировать компонент с помощью RTL, важно использовать функции из библиотеки для рендеринга компонента и взаимодействия с ним. Самый базовый пример выглядит следующим образом:
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';
test('отображение текста', () => {
render(<MyComponent />);
const linkElement = screen.getByText(/привет, мир/i);
expect(linkElement).toBeInTheDocument();
});
Здесь:
render(<MyComponent />) рендерит компонент в
тестовом DOM.screen.getByText(/привет, мир/i) ищет элемент с текстом
“привет, мир” (используется регулярное выражение для поиска).expect(linkElement).toBeInTheDocument() проверяет, что
элемент присутствует в документе.Важной частью тестирования с React Testing Library является работа с
асинхронными операциями, такими как запросы к API или динамическая
загрузка данных. RTL предоставляет утилиту findBy, которая
позволяет ожидать появления элемента в DOM через асинхронные
операции.
Пример асинхронного теста:
import { render, screen, waitFor } from '@testing-library/react';
import MyComponent from './MyComponent';
test('ожидание данных с сервера', async () => {
render(<MyComponent />);
// Предположим, что компонент делает запрос к серверу и отображает данные
const dataElement = await screen.findByText(/загруженные данные/i);
expect(dataElement).toBeInTheDocument();
});
Здесь:
screen.findByText(/загруженные данные/i) ищет элемент с
текстом “загруженные данные” и ждет, пока он появится в DOM.await необходим для того, чтобы дождаться завершения
асинхронной операции.Если компонент зависит от данных с сервера, то для тестирования такого компонента можно использовать библиотеку msw (Mock Service Worker), которая позволяет мокировать API-запросы, не обращаясь к реальному серверу. Для этого можно добавить следующий код в тест:
import { render, screen, waitFor } from '@testing-library/react';
import { server, rest } from 'msw';
import MyComponent from './MyComponent';
// Мокаем API-запрос
beforeAll(() => server.listen());
afterAll(() => server.close());
afterEach(() => server.resetHandlers());
test('загрузка данных с мока', async () => {
server.use(
rest.get('/api/data', (req, res, ctx) => {
return res(ctx.json({ message: 'Мокированные данные' }));
})
);
render(<MyComponent />);
const dataElement = await screen.findByText(/Мокированные данные/i);
expect(dataElement).toBeInTheDocument();
});
Здесь:
server.use позволяет мокировать конкретный запрос.msw позволяет контролировать поведение API-запросов,
делая тесты более стабильными и изолированными от реального
бэкенда.Важным аспектом при написании тестов является выбор правильных
селекторов для поиска элементов в DOM. React Testing Library рекомендует
использовать семантические селекторы, такие как getByRole,
getByLabelText и getByPlaceholderText, которые
лучше всего отражают взаимодействие пользователя с интерфейсом.
Пример с использованием getByRole:
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';
test('кнопка отправки формы', () => {
render(<MyComponent />);
const submitButton = screen.getByRole('button', { name: /отправить/i });
expect(submitButton).toBeInTheDocument();
});
Здесь:
getByRole используется для поиска кнопки с ролью
button и текстом “отправить”.React Testing Library предоставляет удобные методы для симуляции
пользовательских действий, таких как клики или ввод текста. Например,
для имитации клика по кнопке можно использовать метод
fireEvent.click:
import { render, screen, fireEvent } from '@testing-library/react';
import MyComponent from './MyComponent';
test('клик по кнопке изменяет состояние', () => {
render(<MyComponent />);
const button = screen.getByRole('button', { name: /отправить/i });
fireEvent.click(button);
const message = screen.getByText(/успешно отправлено/i);
expect(message).toBeInTheDocument();
});
Здесь:
fireEvent.click(button) имитирует клик по кнопке.Вместо того чтобы сосредотачиваться на внутренней реализации компонента, React Testing Library направлена на тестирование конечного результата и поведения интерфейса.