React Testing Library (RTL) предлагает инструменты для тестирования
компонентов, ориентируясь на поведение пользователя, а не на реализацию.
Одним из ключевых элементов является объект
screen, который служит универсальным
интерфейсом для поиска элементов в виртуальном DOM, созданном в тестах.
Использование screen обеспечивает более чистый и читаемый
код, так как избавляет от необходимости хранить ссылки на рендеринг
компонента в каждой тестовой функции.
screenПосле рендера компонента с помощью render() доступ к
элементам осуществляется через screen:
import { render, screen } from '@testing-library/react';
import Button from './Button';
test('кнопка отображается с текстом', () => {
render(<Button>Нажми меня</Button>);
const buttonElement = screen.getByText('Нажми меня');
expect(buttonElement).toBeInTheDocument();
});
Ключевые моменты:
screen предоставляет унифицированный доступ ко
всем методам поиска элементов.getBy*, queryBy* и
findBy* можно вызывать напрямую через screen,
без деструктуризации объекта, возвращаемого render().screen поддерживает несколько категорий методов,
отличающихся поведением при отсутствии элемента.
getBy* – выбрасывает ошибку, если
элемент не найден.
screen.getByRole('button', { name: /отправить/i });queryBy* – возвращает
null, если элемент отсутствует.
expect(screen.queryByText('Ошибка')).toBeNull();findBy* – асинхронный поиск,
возвращает Promise, полезен при работе с асинхронными
эффектами.
await screen.findByText('Данные загружены');Методы поиска делятся на категории по типу селектора:
getByText,
queryByText, findByText.getByRole,
queryByRole, findByRole.getByLabelText,
queryByLabelText, findByLabelText.getByPlaceholderText.getByAltText,
getByTitle.getByTestId (использовать как
запасной вариант).screen предпочтительнее деструктуризации
render()Ранее стандартным подходом было деструктурировать результат
render:
const { getByText } = render(<Button>Нажми меня</Button>);
getByText('Нажми меня');
Недостатки этого подхода:
Использование screen:
render(<Button>Нажми меня</Button>);
screen.getByText('Нажми меня');
screen активно применяется для тестирования компонентов,
где содержимое появляется после асинхронных операций (например,
fetch-запросов):
render(<AsyncComponent />);
const message = await screen.findByText(/данные загружены/i);
expect(message).toBeInTheDocument();
findBy* автоматически повторяет попытку поиска до
таймаута (по умолчанию 1000 мс).waitFor, если нужно дождаться
состояния компонента:await waitFor(() => {
expect(screen.getByRole('alert')).toHaveTextContent('Ошибка загрузки');
});
screen с пользовательскими событиямиДля имитации взаимодействия с пользователем используют
userEvent:
import userEvent from '@testing-library/user-event';
render(<Button>Кликни меня</Button>);
const button = screen.getByText('Кликни меня');
userEvent.click(button);
expect(button).toBeDisabled();
screen обеспечивает стабильную ссылку на элементы.userEvent имитирует реальные
события браузера.screenПредпочтение ролям (getByRole):
Поиск по ролям более устойчив к изменениям текста.
Пример:
screen.getByRole('button', { name: /сохранить/i });Избегать getByTestId, если
возможно:
TestId оставлять только для сложных случаев, где другие
методы не применимы.Использовать screen.debug() для
отладки:
Выводит текущее состояние DOM.
Полезно для понимания структуры при сложных компонентах:
screen.debug();Проверка отсутствующих элементов:
queryBy* идеально подходит для утверждений об
отсутствии:
expect(screen.queryByText('Загрузка')).toBeNull();Асинхронные проверки:
findBy* или waitFor, чтобы
избежать flaky-тестов.screenscreen в React Testing Library выступает центральным API
для поиска и взаимодействия с элементами виртуального DOM. Он
обеспечивает:
Понимание и грамотное использование screen позволяет
создавать надежные, понятные и легко поддерживаемые тесты для
React-приложений.