React Testing Library (RTL) предоставляет мощные инструменты для тестирования компонентов, но при работе с асинхронным кодом важное значение имеют тайм-ауты и корректная обработка ошибок при ожидании. Неправильное использование этих механизмов может приводить к нестабильным тестам, долгому выполнению и скрытым багам.
Для работы с асинхронными компонентами RTL предлагает функции вида
findBy*, которые возвращают промис:
const button = await screen.findByRole('button', { name: /submit/i });
Эта функция автоматически повторяет поиск элемента в течение определённого времени (по умолчанию 1000 мс). Если элемент не найден, промис отклоняется, и тест завершится с ошибкой.
Тайм-аут можно настраивать через опцию
{ timeout: number }:
const message = await screen.findByText('Загрузка завершена', { timeout: 3000 });
Ключевой момент: слишком маленький тайм-аут приводит к ложным отрицательным результатам, слишком большой — замедляет тесты. Оптимальное значение зависит от ожидаемой длительности асинхронной операции, сетевых задержек и производительности тестового окружения.
Для глобальной настройки тайм-аутов можно использовать
jest.setTimeout:
jest.setTimeout(5000); // увеличивает тайм-аут для всех тестов в файле
Функция waitFor используется для явного ожидания
условия:
await waitFor(() => {
expect(screen.getByText('Данные загружены')).toBeInTheDocument();
}, { timeout: 2000 });
waitFor повторяет выполнение переданного колбэка до тех
пор, пока он не выполнится без ошибок или не истечёт тайм-аут.
Обработка ошибок при ожидании: если внутри
waitFor возникает исключение, RTL продолжает попытки до
истечения тайм-аута. После этого промис отклоняется с ошибкой,
содержащей причину:
Error: Timed out in waitFor.
Можно использовать блок try/catch для явной обработки
ошибок и логирования:
try {
await waitFor(() => expect(screen.getByText('Ошибка загрузки')).toBeInTheDocument(), { timeout: 2500 });
} catch (error) {
console.error('Элемент не появился вовремя', error);
}
getBy* — синхронный поиск, выбрасывает ошибку сразу,
если элемент не найден.queryBy* — синхронный поиск, возвращает
null, если элемент отсутствует.findBy* — асинхронный поиск с повторением до
тайм-аута.Для асинхронных сценариев findBy* и waitFor
являются ключевыми инструментами. Правильное использование
timeout предотвращает нестабильность тестов.
Иногда требуется дождаться изменения состояния компонента или завершения побочных эффектов:
await waitFor(() => {
expect(screen.queryByText('Загрузка...')).not.toBeInTheDocument();
});
Здесь используется queryBy* для проверки отсутствия
элемента. Такой подход предотвращает ложные срабатывания, когда элемент
ещё не удалён из DOM.
При работе с тайм-аутами полезно комбинировать
jest.useFakeTimers и act:
jest.useFakeTimers();
act(() => {
jest.advanceTimersByTime(3000);
});
await waitFor(() => expect(screen.getByText('Готово')).toBeInTheDocument());
Это ускоряет тесты, позволяя контролировать время, не дожидаясь реальных задержек.
findBy* для ожидания появления
элементов.waitFor для проверки изменений состояния
или скрытия элементов.try/catch при необходимости
детального логирования ошибок.jest.useFakeTimers для ускорения тестов.Правильное управление тайм-аутами и обработкой ошибок позволяет создавать надёжные, быстрые и предсказуемые тесты, что особенно важно при тестировании сложных React-компонентов с асинхронными эффектами.