Асинхронные операции — неотъемлемая часть современных Vue-компонентов. Они могут возникать при использовании API-запросов, таймеров, обработчиков событий или watchers. Для корректного тестирования компонентов необходимо понимать, как правильно обрабатывать асинхронность с помощью Vue Test Utils и сопутствующих инструментов, таких как Jest или Vitest.
Vue Test Utils предоставляет методы mount и
shallowMount для рендеринга компонентов. Если компонент
внутри использует асинхронные действия, например mounted()
с async/await или setTimeout, важно дождаться
их завершения, прежде чем делать проверки.
Пример асинхронного mounted:
import { mount } from '@vue/test-utils';
import MyComponent from '@/components/MyComponent.vue';
test('отображает данные после асинхронного запроса', async () => {
const wrapper = mount(MyComponent);
// Дожидаемся завершения всех асинхронных обновлений DOM
await wrapper.vm.$nextTick();
expect(wrapper.text()).toContain('Загруженные данные');
});
Ключевой момент:
await wrapper.vm.$nextTick() позволяет Vue завершить
текущий цикл обновления реактивного состояния. В случае нескольких
асинхронных операций может потребоваться несколько вызовов
await nextTick() или использование более продвинутого
подхода с flushPromises.
Когда компонент работает с промисами, например через
axios или fetch, достаточно одного
nextTick может быть недостаточно. Для этих случаев удобно
использовать пакет flush-promises:
import flushPromises from 'flush-promises';
import { mount } from '@vue/test-utils';
import MyAsyncComponent from '@/components/MyAsyncComponent.vue';
test('загружает и отображает данные', async () => {
const wrapper = mount(MyAsyncComponent);
await flushPromises(); // дожидаемся выполнения всех промисов
expect(wrapper.text()).toContain('Данные с сервера');
});
flushPromises позволяет дождаться всех очередей
микротасков, что особенно полезно при цепочках промисов и асинхронных
методах created или mounted.
Методы компонентов часто выполняют асинхронные действия. Для их
тестирования можно вызывать методы напрямую и использовать
await:
test('метод fetchData обновляет state', async () => {
const wrapper = mount(MyAsyncComponent);
await wrapper.vm.fetchData();
expect(wrapper.vm.data).toEqual(['item1', 'item2']);
});
Важно помнить, что вызов await wrapper.vm.fetchData()
сам по себе не обновляет DOM. Для проверки отображения данных необходимо
дождаться обновления шаблона:
await wrapper.vm.$nextTick();
expect(wrapper.text()).toContain('item1');
Компоненты могут эмитить события после асинхронной операции:
test('эмит события после загрузки данных', async () => {
const wrapper = mount(MyAsyncComponent);
await wrapper.vm.loadData(); // асинхронный метод
await wrapper.vm.$nextTick();
expect(wrapper.emitted('loaded')).toBeTruthy();
});
Совет: если компонент вызывает несколько асинхронных
действий последовательно, лучше использовать flushPromises
для надежного завершения всех промисов, прежде чем проверять события или
DOM.
Асинхронные операции с таймерами требуют управления временем в тестах. Jest предоставляет методы fake timers:
jest.useFakeTimers();
test('отображает сообщение через 1 секунду', async () => {
const wrapper = mount(MyComponentWithTimeout);
jest.advanceTimersByTime(1000); // продвигаем таймер на 1 секунду
await wrapper.vm.$nextTick();
expect(wrapper.text()).toContain('Таймер сработал');
});
Ключевой момент: fake timers позволяют синхронно тестировать асинхронные таймеры без реальной задержки, что ускоряет тесты и делает их детерминированными.
Когда компонент использует watch с асинхронными
действиями, важно дождаться завершения обновлений:
test('watcher обновляет значение после изменения пропса', async () => {
const wrapper = mount(MyComponent, { props: { value: 0 } });
await wrapper.setProps({ value: 42 });
await flushPromises();
expect(wrapper.vm.computedValue).toBe(84);
});
В данном случае flushPromises гарантирует выполнение
всех асинхронных цепочек, запущенных внутри watcher, прежде чем
проверять результат.
nextTick или flushPromises.jest.mock) для API-запросов.Асинхронность в Vue Test Utils требует внимательного контроля цикла реактивности и управления промисами, но правильно структурированные тесты делают поведение компонентов предсказуемым и стабильным.