Поиск и фильтр взаимодействие

React Testing Library предоставляет мощные инструменты для тестирования интерфейсов React-приложений, позволяя проверять как компоненты реагируют на взаимодействие с пользователем. Одним из важных аспектов является проверка поиска и фильтрации данных на основе пользовательских действий. Правильная реализация тестов для поиска и фильтрации позволяет убедиться, что интерфейс работает корректно и реагирует на различные входные данные.

Основы поиска и фильтрации в React

В большинстве приложений существует функциональность поиска и фильтрации, которая позволяет пользователю находить или ограничивать набор данных. Например, в списке товаров может быть форма поиска, которая фильтрует элементы по названию. Важно тестировать такие механизмы, чтобы гарантировать, что они работают корректно в разных сценариях.

Прежде чем приступать к написанию тестов, важно понять, как именно эти функции реализованы. Допустим, существует компонент с фильтрацией списка, который состоит из поля ввода и списка элементов. Пользователь вводит текст в поле, и список обновляется в зависимости от введенного значения.

Поиск элементов с использованием getBy и findBy

React Testing Library предоставляет несколько утилит для поиска элементов на странице. Для реализации тестов поиска и фильтрации обычно используются следующие методы:

  • getBy* — синхронный поиск элементов, возвращающий сразу первый найденный элемент.
  • findBy* — асинхронный поиск элементов, который подходит для случаев, когда элементы могут загружаться с задержкой.

Пример использования getBy для поиска по тексту

Предположим, что на странице есть список пользователей, и мы ищем пользователя по имени. В таком случае можно использовать getByText, чтобы найти элемент, который содержит нужный текст.

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

test('фильтрация пользователей по имени', () => {
  render(<UserList />);
  
  const input = screen.getByPlaceholderText('Поиск по имени');
  userEvent.type(input, 'Иван');
  
  const user = screen.getByText('Иван Иванов');
  expect(user).toBeInTheDocument();
});

Этот пример показывает, как с помощью getByText найти пользователя по имени после того, как в поле ввода введен запрос.

Асинхронный поиск с findBy

Когда элементы загружаются динамически или фильтруются асинхронно, можно использовать findBy. Это важно для проверки, что изменения в интерфейсе действительно произошли после выполнения действия, такого как ввод текста.

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

test('фильтрация пользователей с асинхронной загрузкой', async () => {
  render(<UserList />);
  
  const input = screen.getByPlaceholderText('Поиск по имени');
  userEvent.type(input, 'Иван');
  
  await waitFor(() => {
    const user = screen.getByText('Иван Иванов');
    expect(user).toBeInTheDocument();
  });
});

В этом примере использование waitFor помогает убедиться, что фильтрация прошла успешно и нужный элемент появляется на странице.

Эмуляция ввода текста и взаимодействие с компонентами

В тестах для поиска и фильтрации важно также эмулировать действия пользователя, такие как ввод текста в поле поиска. Для этого используется библиотека user-event, которая предоставляет методы для симуляции событий, таких как userEvent.type для ввода текста.

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

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import SearchableList from './SearchableList';

test('поиск по строке и обновление списка', () => {
  render(<SearchableList />);
  
  const input = screen.getByPlaceholderText('Введите название');
  userEvent.type(input, 'Книга');
  
  const item = screen.getByText('Книга по React');
  expect(item).toBeInTheDocument();
});

Здесь после ввода строки “Книга” в поле поиска происходит фильтрация элементов, и проверяется, что нужный элемент появился на экране.

Использование пользовательских фильтров

Не всегда поиск ограничивается простым текстом. В некоторых приложениях могут быть использованы более сложные фильтры, например, для фильтрации по категориям или дате. В таких случаях важно тестировать взаимодействие с несколькими фильтрами одновременно.

Пример фильтрации по нескольким параметрам:

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import FilteredList from './FilteredList';

test('фильтрация по нескольким параметрам', () => {
  render(<FilteredList />);
  
  const categoryFilter = screen.getByLabelText('Категория');
  userEvent.selectOptions(categoryFilter, 'Книги');
  
  const searchInput = screen.getByPlaceholderText('Поиск');
  userEvent.type(searchInput, 'React');
  
  const filteredItem = screen.getByText('Изучаем React');
  expect(filteredItem).toBeInTheDocument();
});

Этот пример демонстрирует, как можно комбинировать несколько фильтров для более точной настройки поиска. В нем тестируется фильтрация по категории и текстовому запросу одновременно.

Тестирование очистки фильтров

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

Пример теста для очистки фильтров:

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import FilterableList from './FilterableList';

test('очистка фильтров', () => {
  render(<FilterableList />);
  
  const categoryFilter = screen.getByLabelText('Категория');
  userEvent.selectOptions(categoryFilter, 'Техника');
  
  const resetButton = screen.getByText('Сбросить фильтр');
  userEvent.click(resetButton);
  
  const allItems = screen.getAllByRole('listitem');
  expect(allItems.length).toBeGreaterThan(0);
});

В этом примере тестируется кнопка сброса фильтрации. После ее нажатия все элементы должны снова быть видимы на странице.

Тестирование отрицательных сценариев

Также важно учитывать возможные негативные сценарии, когда фильтрация не находит подходящих результатов. Это помогает убедиться, что приложение корректно обрабатывает такие ситуации и отображает правильное сообщение.

Пример теста для негативного сценария:

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import UserList from './UserList';

test('нет результатов для фильтрации', () => {
  render(<UserList />);
  
  const input = screen.getByPlaceholderText('Поиск по имени');
  userEvent.type(input, 'Не существующий пользователь');
  
  const noResultsMessage = screen.getByText('Нет пользователей, соответствующих запросу');
  expect(noResultsMessage).toBeInTheDocument();
});

Здесь проверяется, что при отсутствии результатов фильтрации на странице отображается сообщение об этом.

Заключение

Тестирование поиска и фильтрации в React-приложениях — это важный аспект, который помогает убедиться, что интерфейс работает правильно в различных сценариях. С помощью инструментов React Testing Library можно эмулировать действия пользователя, такие как ввод текста, выбор фильтров, а также тестировать асинхронные обновления данных и взаимодействие с компонентами. Тщательная проверка всех возможных вариантов, включая негативные сценарии и очистку фильтров, позволяет повысить надежность приложения и улучшить пользовательский опыт.