Оптимизация тестов для больших списков

При тестировании компонентов Vue, работающих с большими массивами данных, важно учитывать производительность и точность тестов. Простое рендеринг всего списка в тесте может привести к замедлению сборки и снижению стабильности тестов. Основные подходы включают срезание данных, использование моков и виртуализацию.


Использование shallowMount для снижения нагрузки

shallowMount позволяет монтировать компонент без рендеринга дочерних компонентов полностью. Это особенно полезно, если список содержит вложенные компоненты:

import { shallowMount } from '@vue/test-utils';
import ItemList from '@/components/ItemList.vue';

const items = Array.from({ length: 1000 }, (_, i) => ({ id: i, name: `Item ${i}` }));

const wrapper = shallowMount(ItemList, {
  props: { items }
});

// Проверка наличия нужного количества элементов
expect(wrapper.findAll('li')).toHaveLength(1000);

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


Срезание данных и тестирование выборочно

Тестировать весь массив из тысячи элементов редко нужно. Часто достаточно проверить корректность работы на подмножестве данных:

const smallItems = items.slice(0, 10);

const wrapper = shallowMount(ItemList, {
  props: { items: smallItems }
});

expect(wrapper.findAll('li')).toHaveLength(10);

Такой подход уменьшает количество создаваемых DOM-узлов и снижает время выполнения тестов.

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


Моки для больших массивов

Если компонент вызывает методы для загрузки данных (API, Vuex), их стоит заменять моками. Это уменьшает зависимость тестов от внешних сервисов и ускоряет выполнение.

import { shallowMount } from '@vue/test-utils';
import ItemList from '@/components/ItemList.vue';

const fetchItemsMock = jest.fn(() => Array.from({ length: 1000 }, (_, i) => ({ id: i })));

const wrapper = shallowMount(ItemList, {
  props: { fetchItems: fetchItemsMock }
});

expect(fetchItemsMock).toHaveBeenCalled();

Моки позволяют сфокусироваться на логике рендеринга и обработке данных, игнорируя реальные вызовы API.


Тестирование с виртуализацией

Для рендеринга больших списков в реальном приложении часто используется виртуализация (например, vue-virtual-scroller). В тестах нужно учитывать, что не весь список присутствует в DOM:

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

const wrapper = mount(VirtualList, {
  props: { items }
});

// Проверка, что в DOM отрендерились только видимые элементы
expect(wrapper.findAll('li').length).toBeLessThan(items.length);

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


Использование findAll и фильтрации

При работе с большим списком не рекомендуется выполнять глубокий поиск по всему DOM. Вместо этого используют фильтры и селекторы:

const visibleItems = wrapper.findAll('li').filter(node => node.isVisible());
expect(visibleItems.length).toBeLessThanOrEqual(50);

Совет: избегать использования глобального wrapper.html() для сравнения больших списков, так как это замедляет тест и увеличивает риск ложноположительных результатов.


Проверка реактивности больших списков

Vue Test Utils позволяет проверять реактивные изменения массива через setProps или обновление состояния:

wrapper.setProps({ items: items.slice(0, 20) });
await wrapper.vm.$nextTick();

expect(wrapper.findAll('li')).toHaveLength(20);

Важно: при работе с большими списками следует использовать асинхронные ожидания (await wrapper.vm.$nextTick()), чтобы убедиться, что DOM обновился после изменения данных.


Параметризация тестов

Если требуется проверка различных сценариев с разными размерами списка, удобно использовать describe.each или test.each:

const sizes = [10, 100, 1000];

test.each(sizes)('рендер %i элементов', async (size) => {
  const wrapper = shallowMount(ItemList, {
    props: { items: Array.from({ length: size }, (_, i) => ({ id: i })) }
  });

  expect(wrapper.findAll('li').length).toBe(size);
});

Такой подход уменьшает дублирование кода и систематизирует проверку производительности.


Оптимизация проверки контента

Для больших списков не всегда требуется проверять текст каждого элемента. Достаточно проверить ключевые элементы или шаблон текста:

expect(wrapper.find('li:first-child').text()).toBe('Item 0');
expect(wrapper.find('li:last-child').text()).toBe(`Item ${items.length - 1}`);

Это ускоряет тесты и делает их стабильнее при изменении внутренних данных списка.


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