При тестировании компонентов Vue часто возникает ситуация, когда
внутри компонента выполняются асинхронные операции: HTTP-запросы,
таймеры, события с nextTick, вызовы API или любые
Promise. Для корректной проверки состояния компонента после
завершения этих операций необходим механизм ожидания завершения всех
промисов. В таких случаях используется flushPromises.
flushPromises — это утилита, которая позволяет
«прокинуть» выполнение всех ожидающих промисов до следующего микротаска
JavaScript, обеспечивая стабильное состояние компонента для
проверок.
JavaScript обрабатывает асинхронные задачи через микротаски и макротаски. Промисы попадают в очередь микротасков и выполняются после завершения текущего стека вызовов. В тестах Vue компоненты могут менять своё состояние после завершения промисов, поэтому напрямую проверять DOM после вызова асинхронной функции некорректно — состояние компонента ещё не обновлено.
flushPromises создает промис, который разрешается после
всех уже поставленных в очередь микротасков. Это гарантирует, что все
текущие промисы завершены.
Простейшая реализация:
export default function flushPromises() {
return new Promise(resolve => setImmediate(resolve));
}
Или вариант с использованием Promise и
then:
export default function flushPromises() {
return new Promise(resolve => setTimeout(resolve, 0));
}
Оба подхода создают новый промис, который выполняется после всех предыдущих, позволяя дождаться завершения всех внутренних промисов компонента.
import { mount } from '@vue/test-utils';
import flushPromises from './flushPromises';
import MyComponent from '@/components/MyComponent.vue';
import axios from 'axios';
jest.mock('axios');
test('асинхронный рендер после API-запроса', async () => {
axios.get.mockResolvedValue({ data: { message: 'Привет' } });
const wrapper = mount(MyComponent);
// Компонент отправляет запрос сразу после монтирования
await flushPromises(); // ждём завершения всех промисов
// После flushPromises компонент обновился
expect(wrapper.text()).toContain('Привет');
});
Ключевой момент: без flushPromises
проверка может произойти до завершения промисов, и тест
будет падать даже при правильной логике компонента.
nextTickVue обновляет DOM асинхронно после изменения реактивных данных.
Иногда достаточно await wrapper.vm.$nextTick(), но если
есть цепочки промисов или внешние асинхронные вызовы, одного
$nextTick недостаточно.
await flushPromises();
await wrapper.vm.$nextTick();
Последовательность:
flushPromises завершает все промисы.$nextTick обновляет DOM после изменения состояния.Это гарантирует точность тестов при сложных асинхронных сценариях.
const wrapper = mount(MyComponent);
wrapper.vm.loadData(); // возвращает Promise с цепочкой then
await flushPromises();
expect(wrapper.find('.data').text()).toBe('Данные загружены');
Цепочки промисов, например
axios.get().then(...).then(...), корректно обрабатываются
после вызова flushPromises.
Если внутри компонента используются таймеры (setTimeout)
вместе с промисами:
jest.useFakeTimers();
wrapper.vm.delayedAction(); // вызывает setTimeout и промис внутри
jest.runAllTimers();
await flushPromises();
expect(wrapper.vm.status).toBe('готово');
Сначала выполняются таймеры, затем flushPromises
обеспечивает завершение всех промисов.
flushPromises не отменяет промисы, а
лишь ожидает их завершения.flushPromises особенно
полезен при тестировании реактивных состояний и
watchEffect.flushPromises работает только с микротасками (Promise).
Таймеры и setInterval требуют отдельного контроля через jest
timers.flushPromises повышает
стабильность тестов и предотвращает ложные падения из-за асинхронного
поведения.flushPromises легко интегрируется в любой тестовый
файл:
beforeEach(() => {
jest.clearAllMocks();
});
test('проверка нескольких асинхронных действий', async () => {
axios.get.mockResolvedValueOnce({ data: { value: 1 } });
axios.get.mockResolvedValueOnce({ data: { value: 2 } });
const wrapper = mount(MyComponent);
await flushPromises();
expect(wrapper.find('.first').text()).toBe('1');
expect(wrapper.find('.second').text()).toBe('2');
});
Такой подход позволяет последовательно тестировать несколько асинхронных действий без конфликтов и задержек.
flushPromises становится незаменимым инструментом при
работе с Vue Test Utils, обеспечивая предсказуемое и корректное
тестирование компонентов с любыми асинхронными операциями.