В React Testing Library (RTL) waitFor используется для
ожидания изменений в DOM, которые происходят асинхронно после действий
пользователя или обновления состояния. Основное назначение — проверка,
что компонент правильно реагирует на события, данные или эффекты,
которые происходят с задержкой.
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
await waitFor(() => {
// ожидание выполнения условия
});
Ключевые моменты:
waitFor принимает функцию, которая
должна возвращать результат проверки.findBy и
queryByfindBy также ждёт появления элемента в DOM, но чаще
используется для получения конкретного элемента.queryBy и getBy выполняют
синхронный поиск, не ждут изменений.waitFor применяется, когда необходимо проверить
результат изменения состояния, а не просто наличие
элемента.
Пример: форма с асинхронной отправкой данных.
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Form from './Form';
test('отображает сообщение после успешной отправки', async () => {
render(<Form />);
userEvent.type(screen.getByLabelText(/имя/i), 'Иван');
userEvent.click(screen.getByRole('button', { name: /отправить/i }));
await waitFor(() => {
expect(screen.getByText(/успешно отправлено/i)).toBeInTheDocument();
});
});
Объяснение:
waitFor ждёт, пока DOM обновится с новым
сообщением.waitFor срабатывает только после
появления элемента.waitForИспользование waitFor для синхронных
действий Не нужно оборачивать проверки, которые происходят
мгновенно:
// Неправильно
await waitFor(() => expect(screen.getByText(/текст/i)).toBeInTheDocument());
// Если элемент уже в DOM, waitFor не нуженСлишком длинный код внутри waitFor
Внутри функции лучше помещать только проверку, без
лишней логики или мутаций.
Ожидание элементов, которых нет
waitFor упадёт с ошибкой после таймаута. Если элемент может
отсутствовать, использовать waitFor с условием
expect(...).not.toBeInTheDocument().
waitFor принимает вторым аргументом объект настроек:
await waitFor(() => {
expect(screen.getByText(/данные загружены/i)).toBeInTheDocument();
}, { timeout: 2000, interval: 100 });
Это полезно для тестирования медленных асинхронных операций, например, API-запросов или анимаций.
fireEvent и userEventfireEvent подходит для простых событий, таких как клик
или изменение поля.userEvent эмулирует более реалистичное взаимодействие
пользователя (ввод текста, наведение, клики с задержкой).После таких действий часто требуется waitFor, чтобы
убедиться, что асинхронное обновление DOM произошло.
userEvent.click(screen.getByText(/загрузить/i));
await waitFor(() => {
expect(screen.getByRole('status')).toHaveTextContent('Загрузка завершена');
});
waitFor также используется для ожидания исчезновения
элементов:
await waitFor(() => {
expect(screen.queryByText(/загрузка/i)).not.toBeInTheDocument();
});
Это важно для тестирования компонентов с индикаторами загрузки или модальными окнами, которые скрываются после события.
waitFor только проверки,
не создавая внутри побочных эффектов.findBy, для сложных условий — waitFor.waitFor для синхронных
операций.import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import UserList from './UserList';
test('фильтрация пользователей по имени', async () => {
render(<UserList />);
userEvent.type(screen.getByPlaceholderText(/поиск/i), 'Мария');
await waitFor(() => {
const items = screen.getAllByRole('listitem');
expect(items).toHaveLength(1);
expect(items[0]).toHaveTextContent('Мария');
});
});
Здесь waitFor обеспечивает корректное ожидание
обновления списка после ввода текста и асинхронной фильтрации.
Этот подход делает тесты устойчивыми к асинхронности, повышает их читаемость и минимизирует ошибки, связанные с опережением проверки DOM до завершения событий.