Understand screen object и его возможности

В React Testing Library (RTL) объект screen является центральным инструментом для взаимодействия с DOM в тестах. Он предоставляет единый интерфейс для поиска элементов на странице и является предпочтительным подходом по сравнению с возвратом результатов из render напрямую. Использование screen повышает читаемость тестов и снижает необходимость явно деструктурировать возвращаемые значения.


Основные принципы работы с screen

screen — это глобальный объект, который содержит методы поиска элементов. При рендеринге компонента с помощью render DOM автоматически подключается к screen, что позволяет использовать его методы без дополнительного присвоения.

import { render, screen } from '@testing-library/react';
import Button from './Button';

render(<Button>Click me</Button>);

const button = screen.getByText('Click me');

Ключевые моменты:

  • screen работает с реальным DOM, созданным в тестовом окружении.
  • Он инкапсулирует результаты рендера, что позволяет писать более чистые тесты.
  • Использование screen делает тесты более декларативными, так как поиск элементов происходит через понятные методы.

Методы поиска в screen

Методы поиска в screen делятся на несколько категорий, в зависимости от того, как они ведут себя при отсутствии элемента:

  1. Методы, вызывающие исключение при отсутствии элемента (getBy*):

    • getByText()
    • getByRole()
    • getByLabelText()
    • getByPlaceholderText()
    • getByAltText()
    • getByTitle()

    Пример:

    const input = screen.getByLabelText('Username');
  2. Методы, возвращающие массив элементов (getAllBy*):

    • Используются, когда на странице может быть несколько совпадений.
    • Если совпадений нет, вызывается ошибка.
    const items = screen.getAllByRole('listitem');
  3. Методы, возвращающие null при отсутствии элемента (queryBy*):

    • Удобны для проверки отсутствия элемента на странице.
    • Не выбрасывают исключение, а возвращают null.
    expect(screen.queryByText('Loading...')).toBeNull();
  4. Асинхронные методы (findBy*):

    • Используются для элементов, которые появляются не сразу (например, после загрузки данных).
    • Возвращают промис, который резолвится, когда элемент появляется, или выбрасывают ошибку при таймауте.
    const user = await screen.findByText('John Doe');

Поиск элементов по роли

Метод getByRole является самым рекомендуемым способом поиска элементов в RTL, так как он ориентирован на доступность (accessibility). Он учитывает такие атрибуты, как aria-label и aria-labelledby, и позволяет тестировать компоненты с точки зрения пользователя.

const submitButton = screen.getByRole('button', { name: /submit/i });
  • Аргумент name позволяет уточнить элемент по видимому тексту или aria-label.
  • Использование ролей делает тесты более стабильными, чем поиск по классу или селектору.

Поиск по тексту

Методы getByText и queryByText позволяют искать элементы по видимому тексту. Можно использовать строки или регулярные выражения.

const welcomeMessage = screen.getByText(/welcome, john/i);
  • Поддержка регистронезависимого поиска через регулярные выражения.
  • Полезно для текстовых компонентов, сообщений об ошибках или заголовков.

Поиск по лейблам и плейсхолдерам

  • getByLabelText() — связывает <label> и <input> через for или вложенность.
  • getByPlaceholderText() — ищет элементы по атрибуту placeholder.
const emailInput = screen.getByLabelText('Email');
const searchInput = screen.getByPlaceholderText('Search...');

Эти методы делают тесты более декларативными и читаемыми, поскольку они отражают пользовательский опыт.


Проверка отсутствия элемента

Комбинация queryBy* и Jest-матчеров позволяет проверять, что элемент не отображается.

expect(screen.queryByText('Error')).not.toBeInTheDocument();
  • Отличается от getBy*, который выбросит ошибку.
  • Идеально подходит для тестирования условий рендеринга, ошибок или модальных окон.

Асинхронный поиск и ожидание элементов

findBy* методы используют встроенный таймаут и повторный поиск, что позволяет работать с компонентами, которые изменяют DOM после событий или асинхронных операций.

const profileName = await screen.findByText('Alice');
  • Внутренне использует waitFor для ожидания элемента.
  • Позволяет избежать использования ручного setTimeout или дополнительных промисов.

Преимущества использования screen

  1. Единый интерфейс для всех тестов, что повышает читаемость.
  2. Отделение рендера от поиска, что улучшает поддержку и рефакторинг.
  3. Поддержка подхода ориентированного на пользователя: поиск по роли, тексту, лейблу.
  4. Стабильность тестов: меньше привязки к внутренней структуре DOM.
  5. Совместимость с асинхронными компонентами, работающими с API или задержками.

Практические рекомендации

  • Всегда отдавать предпочтение screen вместо деструктурирования render, например:

    render(<App />);
    screen.getByText('Hello World');
  • Использовать getByRole для интерактивных элементов, чтобы тесты отражали доступность.

  • Для проверки отсутствия элементов использовать queryBy*.

  • Для динамических компонентов использовать findBy*, чтобы дождаться появления элементов.

  • Избегать тестирования по классам и селекторам, так как это делает тесты хрупкими.


Объект screen является ядром поиска элементов в React Testing Library, позволяя писать тесты чисто, декларативно и стабильно. Владение его методами и понимание различий между getBy*, queryBy* и findBy* позволяет создавать тесты, ориентированные на пользователя, и поддерживать их при развитии приложения.