Что такое RTL и её функциональность

React Testing Library (RTL) — это инструмент для тестирования компонентов React, ориентированный на взаимодействие пользователя с приложением, а не на внутреннюю реализацию компонентов. Основная цель RTL — проверять поведение интерфейса так, как его видит пользователь, а не структуру компонентов или состояние их внутренних методов.

Основные принципы React Testing Library

  1. Тестирование через пользовательский опыт RTL фокусируется на том, чтобы тесты отражали действия пользователя: клики, ввод текста, навигацию и видимость элементов. Это обеспечивает более устойчивые тесты к изменениям реализации компонентов.

  2. Минимизация тестирования внутренней реализации Не следует проверять приватные методы компонентов или состояние React напрямую. Тесты должны опираться на DOM и видимые элементы, а не на внутренние детали.

  3. Легкость интеграции с Jest и другими фреймворками RTL не предоставляет собственный раннер тестов. Обычно он используется вместе с Jest, что обеспечивает мощные возможности для асинхронного тестирования, мокирования и проверки ожиданий.


Основные функции и методы RTL

render()

Функция render создаёт виртуальное представление компонента в тестовой среде и возвращает объект с методами для взаимодействия с DOM.

import { render } from '@testing-library/react';
import App from './App';

const { getByText, queryByText } = render(<App />);

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

  • Позволяет получать элементы через селекторы (getByText, getByRole, getByLabelText).
  • Возвращает объект, содержащий контейнер DOM, утилиты для поиска элементов и методы обновления.
  • Можно передавать контексты, провайдеры, темы или роутеры для интеграционного тестирования.

Поиск элементов

RTL предоставляет несколько категорий методов поиска элементов:

  1. getBy…

    • getByText, getByRole, getByLabelText
    • Возвращает элемент, если он найден, иначе выбрасывает ошибку.
    • Используется, когда элемент обязательно должен быть в DOM.
  2. queryBy…

    • queryByText, queryByRole
    • Возвращает элемент или null, если он отсутствует.
    • Удобно для проверки отсутствия элементов.
  3. findBy…

    • Асинхронные версии getBy…, возвращают Promise, который разрешается, когда элемент появляется в DOM.
    • Используются для тестирования асинхронного поведения, например, после загрузки данных.

Пример:

const { getByText, queryByText, findByText } = render(<App />);
expect(getByText('Привет')).toBeInTheDocument();
expect(queryByText('Ошибка')).toBeNull();
await expect(findByText('Загрузка завершена')).resolves.toBeInTheDocument();

Взаимодействие с элементами (user-event)

Для симуляции действий пользователя используется библиотека @testing-library/user-event. Она позволяет выполнять клики, ввод текста, навигацию по клавиатуре.

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

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

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

Преимущества user-event перед fireEvent:

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

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

Тестирование компонентов с асинхронным поведением (запросы к API, таймеры, анимации) требует использования утилит для ожидания. Основные методы:

  • waitFor — ждет, пока внутри callback не выполнятся проверки.
  • findBy… — асинхронный поиск элементов с таймаутом.
import { waitFor } from '@testing-library/react';

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

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

RTL легко интегрируется с контекстами React и библиотеками мокирования, такими как Jest:

import { render } from '@testing-library/react';
import { ThemeProvider } from 'styled-components';
import App from './App';
import theme from './theme';

render(
  <ThemeProvider theme={theme}>
    <App />
  </ThemeProvider>
);

Таким образом, можно тестировать компоненты в среде, максимально приближенной к реальному приложению.


Полезные рекомендации

  • Отдавать предпочтение селекторам по роли и тексту, а не по id или className.
  • Проверять видимые эффекты действий пользователя, а не внутренние состояния.
  • Использовать асинхронные методы, когда есть задержки или загрузка данных.
  • Комбинировать RTL с Jest для мокирования fetch, функций и таймеров.

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