React Testing Library (RTL) предоставляет разнообразные методы для
поиска элементов в DOM, и среди них особое место занимают
асинхронные методы поиска. Они реализуются через
префикс findBy и служат для сценариев, когда элементы
появляются в DOM с задержкой, например, после выполнения асинхронного
запроса или обновления состояния.
findByМетоды findBy являются асинхронными и возвращают
промис, который разрешается в элемент, как только он появляется
в DOM. Если элемент не найден за установленный таймаут (по умолчанию
1000 мс), промис отклоняется с ошибкой.
Синтаксис:
const element = await screen.findByRole('button', { name: /submit/i });
screen — стандартный объект RTL для поиска
элементов.findByRole — ищет элемент по роли (role) и
возвращает промис.name,
exact или hidden.findByReact Testing Library предоставляет полный набор findBy
методов, аналогичный синхронным getBy:
findByText — ищет по текстовому содержимому.findByRole — ищет по роли элемента (рекомендованный
способ для доступности).findByLabelText — ищет по связанным с элементом
<label>.findByPlaceholderText — ищет по атрибуту
placeholder.findByAltText — ищет по альтернативному тексту
изображения.findByTitle — ищет по атрибуту title.findByTestId — ищет по data-testid
(используется в крайнем случае).Каждый метод возвращает промис, что позволяет
использовать async/await или .then().
getBy и
queryBy| Метод | Возвращаемое значение | Поведение при отсутствии элемента |
|---|---|---|
getBy... |
Элемент DOM | Бросает ошибку сразу |
queryBy... |
Элемент DOM или null |
Возвращает null, ошибок нет |
findBy... |
Промис, который резолвится в элемент | Асинхронно ждет появления, бросает ошибку по таймауту |
Использование findBy оправдано, когда элемент не
появляется мгновенно после рендера, например, при:
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import AsyncButton from './AsyncButton';
test('кнопка появляется после запроса', async () => {
render(<AsyncButton />);
// Кликаем, чтобы инициировать асинхронное действие
userEvent.click(screen.getByText(/загрузить/i));
// Асинхронно ожидаем появления кнопки
const button = await screen.findByRole('button', { name: /подтвердить/i });
expect(button).toBeInTheDocument();
});
В этом примере:
findByRole ждет, пока кнопка с текстом “Подтвердить”
появится в DOM.toBeInTheDocument() выполняется только после
того, как элемент найден.Методы findBy поддерживают настройку таймаута и
интервала повторного поиска через объект
options:
const element = await screen.findByText('Загрузка завершена', {
exact: true,
timeout: 2000 // ждать до 2 секунд
});
timeout — максимальное время ожидания в
миллисекундах.exact — учитывать точное совпадение текста
(true по умолчанию).Эти параметры позволяют контролировать асинхронное поведение тестов и снижать вероятность ложноположительных ошибок.
findAllByДля поиска нескольких элементов асинхронно
используется findAllBy:
const items = await screen.findAllByRole('listitem');
expect(items).toHaveLength(3);
findBy оправдано только при
асинхронном рендере. Для синхронных элементов лучше
использовать getBy.findBy всегда применять await,
иначе проверка не дождется элемента.waitFor допустимо, но чаще
findBy полностью заменяет необходимость в
waitFor.Асинхронный поиск особенно полезен после событий, которые запускают обновление DOM:
userEvent.click(screen.getByText('Загрузить'));
const message = await screen.findByText('Данные загружены');
expect(message).toBeVisible();
findBy автоматически повторяет поиск с небольшими
интервалами.Методы findBy и findAllBy в React Testing
Library позволяют:
role,
label и текст, повышая доступность.Использование findBy — это ключ к надежным тестам в
современном React-приложении, где асинхронные операции и динамическое
отображение контента стали нормой.