Фильтрация результатов поиска

Vue Test Utils (VTU) — официальная библиотека для тестирования компонентов Vue. Она предоставляет удобный API для рендеринга компонентов, поиска элементов внутри них и проверки их поведения. В контексте фильтрации результатов поиска основное внимание уделяется тому, как тестировать динамическое отображение данных на основе пользовательского ввода и состояния компонентов.

Рендеринг компонента и создание обёртки

Тестирование фильтрации начинается с рендеринга компонента с помощью mount или shallowMount. Выбор метода зависит от необходимости тестировать дочерние компоненты:

import { mount } from '@vue/test-utils';
import SearchComponent from '@/components/SearchComponent.vue';

const wrapper = mount(SearchComponent, {
  props: {
    items: [
      { id: 1, name: 'Apple' },
      { id: 2, name: 'Banana' },
      { id: 3, name: 'Orange' }
    ]
  }
});

Ключевой момент: mount полностью рендерит компонент, включая всех потомков, что позволяет проверять взаимодействие дочерних элементов. shallowMount игнорирует дочерние компоненты, что ускоряет тесты и изолирует логику.

Симуляция пользовательского ввода

Фильтрация обычно запускается изменением значения в поле ввода. VTU предоставляет методы setValue и trigger для имитации событий:

const input = wrapper.find('input[type="text"]');
await input.setValue('Ap');
await input.trigger('input');

Ключевой момент: важно использовать await, так как изменение значения может запускать асинхронные обновления компонента через v-model или реактивные вычисляемые свойства.

Проверка состояния фильтрованных данных

После ввода данных следует проверить, что компонент отобразил только элементы, соответствующие фильтру:

const results = wrapper.findAll('.search-item');
expect(results).toHaveLength(1);
expect(results[0].text()).toBe('Apple');

Рекомендация: использовать CSS-классы или data-атрибуты для точного поиска элементов. Это снижает вероятность поломки теста при изменении разметки.

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

Многие компоненты реализуют фильтрацию через вычисляемые свойства:

computed: {
  filteredItems() {
    return this.items.filter(item =>
      item.name.toLowerCase().includes(this.query.toLowerCase())
    );
  }
}

Тестирование таких вычисляемых свойств можно вести через изменение состояния компонента:

await wrapper.setData({ query: 'an' });
const filtered = wrapper.findAll('.search-item');
expect(filtered).toHaveLength(2);
expect(filtered.map(f => f.text())).toEqual(expect.arrayContaining(['Banana', 'Orange']));

Ключевой момент: setData обновляет реактивное состояние и автоматически инициирует пересчёт вычисляемых свойств, что делает тест максимально приближённым к реальному поведению.

Обработка пустого состояния и ошибок

Необходимо проверять сценарии, когда фильтр не возвращает результатов или список изначально пуст:

await wrapper.setData({ query: 'xyz' });
const emptyMessage = wrapper.find('.no-results');
expect(emptyMessage.exists()).toBe(true);
expect(emptyMessage.text()).toBe('Нет результатов');

Рекомендация: тестировать как позитивные, так и негативные сценарии, чтобы убедиться в корректной обработке всех состояний компонента.

Проверка асинхронной фильтрации

Если фильтрация данных зависит от API-запроса, VTU позволяет мокировать методы или сервисы:

jest.spyOn(wrapper.vm, 'fetchItems').mockResolvedValue([
  { id: 1, name: 'Apple' }
]);

await wrapper.vm.fetchItems('Ap');
await wrapper.vm.$nextTick();

const results = wrapper.findAll('.search-item');
expect(results).toHaveLength(1);

Ключевой момент: использование jest.spyOn или моков позволяет изолировать компонент и тестировать только его логику фильтрации без сетевых зависимостей.

Комбинированные сценарии фильтрации

Тесты могут проверять сложные сценарии, например, фильтрацию с сортировкой или пагинацией:

await wrapper.setData({ query: 'a', sortBy: 'name' });
const items = wrapper.findAll('.search-item');
expect(items[0].text()).toBe('Apple');
expect(items[1].text()).toBe('Banana');

Совет: разделение логики фильтрации и рендеринга на вычисляемые свойства и методы упрощает написание таких комплексных тестов.

Практика устойчивого тестирования

  • Использовать точные селекторы (data-test, aria-label) вместо селекторов по стилям.
  • Проверять как состояние DOM, так и внутренние вычисляемые свойства.
  • Разделять тесты на небольшие блоки: ввод, фильтрация, пустое состояние, асинхронные сценарии.
  • Применять мокирование для внешних сервисов и API-запросов.

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