waitFor — это утилита из React Testing Library,
предназначенная для ожидания асинхронных изменений в DOM. Она особенно
полезна при тестировании компонентов, которые обновляют интерфейс после
выполнения асинхронных операций, таких как запросы к API, таймеры или
события пользователя.
Сигнатура функции:
await waitFor(callback, options?)
callback — функция, внутри которой проверяется
состояние DOM. Если условие не выполняется, waitFor будет
повторно вызывать callback до истечения таймаута.
options — объект с настройками:
timeout — максимальное время ожидания (по умолчанию
1000 мс).interval — интервал между проверками состояния (по
умолчанию 50 мс).onTimeout — функция, вызываемая при превышении
таймаута.Простейший пример:
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import MyComponent from './MyComponent';
test('кнопка появляется после клика', async () => {
render(<MyComponent />);
userEvent.click(screen.getByText('Показать кнопку'));
await waitFor(() => {
expect(screen.getByText('Новая кнопка')).toBeInTheDocument();
});
});
В этом примере waitFor ожидает появления элемента в DOM
после асинхронного обновления.
Повторное выполнение колбэка
waitFor выполняет переданный колбэк до тех пор, пока:
expect(element).toBeInTheDocument()), либоОбработка ошибок Если внутри
callback возникает ошибка (например, элемент ещё не
существует), waitFor перехватывает её и продолжает
повторные попытки. После превышения таймаута ошибка выбрасывается
снова.
Асинхронное ожидание waitFor
возвращает Promise, поэтому его необходимо использовать с
await внутри асинхронной функции test или
it.
Не использовать waitFor без
необходимости Для синхронных изменений DOM лучше использовать
прямые проверки. waitFor оправдан только при асинхронных
обновлениях.
Избегать сложной логики внутри callback Колбэк должен содержать только проверки состояния DOM. Логика изменения данных должна оставаться в тестируемом компоненте.
Настройка таймаута Для операций с длительным
временем отклика (например, запросы к реальному API) стоит увеличить
timeout:
await waitFor(
() => expect(screen.getByText('Данные загружены')).toBeInTheDocument(),
{ timeout: 3000 }
);Комбинация с findBy Методы
findBy* (findByText, findByRole)
используют waitFor под капотом и являются удобной
альтернативой для одиночных асинхронных проверок:
const button = await screen.findByText('Новая кнопка');
expect(button).toBeInTheDocument();Избегать ожидания постоянного состояния
waitFor не предназначен для непрерывного отслеживания DOM.
Он завершает работу, как только callback перестаёт выбрасывать ошибку
или истекает таймаут.
onTimeout — позволяет задать кастомное сообщение при превышении таймаута:
await waitFor(
() => expect(screen.getByText('Готово')).toBeInTheDocument(),
{
timeout: 2000,
onTimeout: () => console.error('Элемент не появился за 2 секунды')
}
);interval — позволяет контролировать частоту проверок. Уменьшение интервала делает проверку более «чуткой», увеличение снижает нагрузку:
await waitFor(
() => expect(screen.getByText('Прогресс')).toBeInTheDocument(),
{ interval: 100 }
);Использование с асинхронными запросами Для
компонентов, которые получают данные через fetch или
axios, waitFor позволяет безопасно дождаться
обновления DOM после завершения промиса:
test('данные загружаются и отображаются', async () => {
render(<DataComponent />);
await waitFor(() => expect(screen.getByText('Загружено')).toBeInTheDocument());
});Преждевременный вызов expect без
waitFor Проверка асинхронного изменения до его
завершения приведёт к ошибке. Решение — обернуть expect в
waitFor.
Слишком короткий таймаут Асинхронные операции могут занимать больше времени, чем задано по умолчанию. Таймаут стоит подбирать с запасом.
Возврат значения из callback
waitFor игнорирует возвращаемое значение колбэка,
проверяется только отсутствие выброшенной ошибки.
Вложенные асинхронные ожидания Не стоит
использовать waitFor внутри других waitFor —
это может привести к неопределённому поведению и увеличению времени
теста.
render компонента всегда должен быть первым шагом.waitFor.waitFor.setTimeout в тесте,
предпочитая ожидание конкретных изменений DOM.Использование waitFor обеспечивает надёжное тестирование
асинхронных компонентов, гарантируя, что проверки DOM выполняются только
после фактического обновления интерфейса. Это ключевой инструмент для
создания стабильных и предсказуемых тестов в React Testing Library.