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) вместо селекторов по стилям.Эти подходы обеспечивают высокую надёжность и предсказуемость тестов Vue компонентов с фильтрацией, минимизируя вероятность ложноположительных и ложноотрицательных результатов.