Query параметры тестирование

Тестирование React-компонентов часто требует взаимодействия с DOM и проверок элементов на основе различных условий. Одним из ключевых аспектов является использование query-параметров, предоставляемых React Testing Library, для поиска элементов на странице и взаимодействия с ними в тестах.

Основные типы query-параметров

React Testing Library предоставляет несколько категорий методов поиска, каждая из которых подходит для определённых сценариев тестирования:

  1. getBy Методы типа getBy используются, когда элемент обязательно должен существовать в DOM. Если элемент не найден, тест сразу завершится с ошибкой. Примеры:

    import { render, screen } from '@testing-library/react';
    import Button from './Button';
    
    render(<Button text="Click me" />);
    const button = screen.getByText('Click me');
    expect(button).toBeInTheDocument();
  2. queryBy Методы типа queryBy возвращают null, если элемент не найден. Их используют, когда нужно проверить отсутствие элемента. Пример:

    render(<Button />);
    const hiddenText = screen.queryByText('Не существует');
    expect(hiddenText).toBeNull();
  3. findBy Асинхронная альтернатива getBy, которая возвращает промис и ожидает появления элемента в DOM. Используется при тестировании компонентов с асинхронными обновлениями состояния, например после запроса к API. Пример:

    render(<AsyncButton />);
    const asyncButton = await screen.findByText('Загрузка завершена');
    expect(asyncButton).toBeVisible();
  4. getAllBy / queryAllBy / findAllBy Позволяют искать несколько элементов одновременно, возвращая массив найденных узлов. Если элементов нет, getAllBy бросает ошибку, а queryAllBy возвращает пустой массив.

    render(<ul><li>Item 1</li><li>Item 2</li></ul>);
    const items = screen.getAllByRole('listitem');
    expect(items.length).toBe(2);

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

Методы query поддерживают различные критерии:

  • TextgetByText, queryByText, findByText Ищет элементы по видимому тексту. Позволяет использовать регулярные выражения для частичного совпадения.

  • RolegetByRole, queryByRole, findByRole Используется для проверки элементов по их семантической роли (кнопка, заголовок, поле ввода). Часто комбинируется с опцией name, чтобы уточнить конкретный элемент.

    const submitButton = screen.getByRole('button', { name: /submit/i });
  • LabelTextgetByLabelText Находит элементы формы, связанные с <label>. Позволяет проверять поля ввода и их соответствие меткам.

  • PlaceholderTextgetByPlaceholderText Поиск по тексту placeholder в полях ввода.

  • AltTextgetByAltText Используется для поиска изображений по атрибуту alt.

  • TitlegetByTitle Поиск элементов по атрибуту title.

  • TestIdgetByTestId Прямой поиск по data-testid. Часто используется, когда другие селекторы не подходят, но предпочтение всегда отдают семантическим методам.

Особенности использования query-параметров

  1. Приоритет семантики Поиск элементов через роль, текст или метку предпочтительнее, чем через data-testid. Это делает тесты ближе к пользовательскому опыту.

  2. Асинхронные проверки findBy методы особенно полезны при ожидании появления элементов после асинхронных операций, таких как загрузка данных или анимации.

  3. Комбинация критериев Методы поиска поддерживают объект опций, позволяющий уточнить элемент. Например, поиск кнопки с определённым именем и состоянием:

    screen.getByRole('button', { name: /Отправить/i, hidden: true });
  4. Отслеживание отсутствия элементов Использование queryBy или queryAllBy позволяет писать тесты для сценариев, где элементы должны исчезнуть из DOM после определённых действий.

  5. Множественные элементы Для списков или таблиц удобнее использовать getAllBy или queryAllBy, чтобы проверить количество и содержимое элементов.

Практические примеры

Проверка текста кнопки после клика:

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

render(<ToggleButton />);
const button = screen.getByText('Включить');
fireEvent.click(button);
expect(screen.getByText('Выключить')).toBeInTheDocument();

Асинхронная загрузка данных:

render(<UserList />);
const users = await screen.findAllByRole('listitem');
expect(users.length).toBeGreaterThan(0);

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

render(<Notification message="Ошибка" />);
const closeButton = screen.getByRole('button', { name: /закрыть/i });
fireEvent.click(closeButton);
expect(screen.queryByText('Ошибка')).toBeNull();

Формы и их поля:

render(<LoginForm />);
const username = screen.getByLabelText('Имя пользователя');
const password = screen.getByLabelText('Пароль');
expect(username).toBeInTheDocument();
expect(password).toBeInTheDocument();

Использование query-параметров в React Testing Library позволяет создавать точные, семантически корректные и устойчивые к изменениям DOM тесты, ориентированные на поведение приложения, а не на детали реализации. Такой подход упрощает поддержку тестов и делает их более читаемыми для команды разработки.