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

React Testing Library предоставляет набор функций для поиска элементов в DOM при тестировании компонентов. Среди этих функций особое место занимают queryBy методы, используемые для проверки отсутствия элементов. В отличие от getBy методов, которые выбрасывают ошибку при отсутствии элемента, queryBy методы возвращают null, что делает их удобными для тестов на непоявление элементов.

Отличие queryBy от getBy и findBy

  • getBy – выбрасывает ошибку, если элемент не найден. Используется для тестирования наличия элементов.
  • queryBy – возвращает null при отсутствии элемента, подходит для тестирования отсутствия элементов.
  • findBy – возвращает промис, используется для асинхронного поиска элементов.

Пример различий:

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

render(<MyComponent />);

// getBy выбросит ошибку, если кнопка не найдена
screen.getByText('Submit');

// queryBy вернет null, если кнопка не найдена
const button = screen.queryByText('Submit');
expect(button).toBeNull();

Основные queryBy методы

React Testing Library предоставляет несколько основных queryBy методов, соответствующих getBy методам:

  • queryByText – поиск по текстовому содержимому.
  • queryByRole – поиск по роли элемента.
  • queryByLabelText – поиск по тексту связанной с элементом метки <label>.
  • queryByPlaceholderText – поиск по placeholder.
  • queryByAltText – поиск по атрибуту alt (для изображений).
  • queryByTitle – поиск по атрибуту title.
  • queryByDisplayValue – поиск по текущему значению элемента формы.

Пример использования queryByText:

const { queryByText } = render(<div>Заголовок</div>);

expect(queryByText('Заголовок')).not.toBeNull(); // элемент существует
expect(queryByText('Не существует')).toBeNull(); // элемента нет

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

Основное назначение queryBy методов – подтверждение отсутствия элементов на странице. Для таких проверок удобно использовать Jest матчер toBeNull() или not.toBeInTheDocument().

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

render(<div><p>Контент</p></div>);

expect(screen.queryByText('Не существует')).toBeNull();
expect(screen.queryByText('Не существует')).not.toBeInTheDocument();

Ключевой момент: не следует использовать getBy методы для проверки отсутствия элементов, так как они сразу выбросят ошибку при отсутствии, делая тест некорректным.

queryByRole для тестирования UI компонентов

Метод queryByRole особенно полезен для проверки отсутствия интерактивных элементов: кнопок, ссылок, чекбоксов.

render(<button>Нажми меня</button>);

expect(screen.queryByRole('button', { name: 'Не существует' })).toBeNull();
expect(screen.queryByRole('button', { name: 'Нажми меня' })).not.toBeNull();

queryByRole поддерживает фильтры по атрибутам, что позволяет гибко проверять отсутствие или наличие элементов с определёнными характеристиками.

Асинхронные сценарии и queryBy

Для асинхронных действий, когда элемент может появиться с задержкой, queryBy методы не ждут появления. В таких случаях нужно использовать findBy, возвращающий промис. Однако queryBy удобно использовать после асинхронных событий для проверки исчезновения элемента:

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

render(<Modal />);

// Закрываем модальное окно
fireEvent.click(screen.getByText('Закрыть'));

expect(screen.queryByText('Модальное окно')).toBeNull();

Советы по использованию queryBy

  1. Проверка отрицательных сценариев: идеально подходит для тестов, где элемент не должен отображаться.
  2. Избегать getBy для отрицательных проверок: getBy выбросит исключение и тест не сможет корректно обработать отсутствие элемента.
  3. Комбинация с jest-dom матчерами: toBeInTheDocument() делает тесты более читаемыми.
  4. Использование фильтров и опций: queryBy поддерживает name, exact, selector и другие параметры, повышающие точность теста.

Практический пример комплексного теста

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

test('уведомление исчезает после закрытия', () => {
  render(<Notification message="Событие успешно!" />);

  // Проверяем, что уведомление отображается
  expect(screen.queryByText('Событие успешно!')).not.toBeNull();

  // Симулируем закрытие уведомления
  fireEvent.click(screen.getByRole('button', { name: /закрыть/i }));

  // Проверяем, что уведомление исчезло
  expect(screen.queryByText('Событие успешно!')).toBeNull();
});

В этом примере queryBy методы обеспечивают безопасную проверку исчезновения элементов, без риска выброса исключения, что делает тесты стабильными и предсказуемыми.

Итоговое применение

QueryBy методы предназначены для:

  • Проверки отсутствия элементов.
  • Тестирования условных рендеров, где компонент может быть не отрендерен.
  • Сценариев скрытия элементов после действий пользователя.

Использование этих методов повышает читаемость тестов и снижает вероятность ложных срабатываний, обеспечивая точное соответствие тестов поведению интерфейса.