Функция flushPromises()

flushPromises() — это утилита, используемая в тестировании компонентов Vue для управления асинхронными процессами. Она позволяет дождаться завершения всех промисов в очереди микротасков, что особенно важно при тестировании компонентов, использующих асинхронные вызовы, такие как API-запросы, nextTick, таймеры с Promise или асинхронные вычисляемые свойства.


Принцип работы

JavaScript обрабатывает асинхронный код через микротаски и макротаски. Промисы помещаются в очередь микротасков, которая выполняется после текущего стека вызовов, но до следующей макротаски. В тестах Vue это может приводить к ситуации, когда компоненты еще не обновили состояние после асинхронных операций, а утверждения (assert) выполняются сразу. flushPromises() решает эту проблему, принудительно ожидая завершения всех промисов перед проверкой состояния компонента.

Простейшая реализация flushPromises() выглядит так:

export function flushPromises() {
  return new Promise(resolve => setTimeout(resolve, 0));
}

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


Использование с Vue Test Utils

flushPromises() обычно применяется вместе с функцией mount или shallowMount из @vue/test-utils для тестирования компонентов с асинхронными эффектами. Рассмотрим пример:

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);

  // Компонент инициирует API-запрос в mounted()
  await flushPromises();

  expect(wrapper.text()).toContain('Привет');
});

В этом примере вызов flushPromises() гарантирует, что все промисы, созданные в mounted(), будут завершены до проверки содержимого компонента.


Работа с асинхронными методами и событиями

flushPromises() полезна при тестировании методов, возвращающих промисы, и событий, которые инициируют асинхронные процессы.

test('обновление состояния после асинхронного метода', async () => {
  const wrapper = mount(MyComponent);

  wrapper.vm.loadData(); // метод возвращает промис
  await flushPromises();

  expect(wrapper.vm.dataLoaded).toBe(true);
});

Здесь flushPromises() обеспечивает синхронизацию теста с внутренним состоянием компонента, обновленным после завершения промиса.


Сочетание с nextTick

Vue использует реактивность через механизм реактивных эффектов и очередь обновлений. Иногда после асинхронного промиса нужно дождаться обновления DOM. В таких случаях flushPromises() комбинируют с nextTick():

import { nextTick } from 'vue';

await flushPromises();
await nextTick();

expect(wrapper.find('p').text()).toBe('Данные загружены');
  • flushPromises() дожидается завершения всех промисов.
  • nextTick() гарантирует, что Vue обновил DOM на основе изменений реактивного состояния.

Тестирование ошибок промисов

flushPromises() также позволяет корректно тестировать обработку ошибок:

axios.get.mockRejectedValue(new Error('Ошибка загрузки'));

const wrapper = mount(MyComponent);
await flushPromises();

expect(wrapper.text()).toContain('Ошибка загрузки');

Без flushPromises() промис, выбросивший ошибку, может остаться незавершенным, и тест не сможет проверить отображение сообщения об ошибке.


Ограничения и нюансы

  1. Только промисы текущей микротаски: flushPromises() не гарантирует завершение промисов, которые создаются внутри промисов после первого вызова. В таких случаях может потребоваться несколько последовательных вызовов flushPromises().
  2. Синхронизация с Vue реактивностью: после flushPromises() рекомендуется использовать nextTick() для проверки DOM.
  3. Не заменяет мокирование таймеров: если используется setTimeout или setInterval, их необходимо контролировать через Jest таймеры или библиотеку vi.useFakeTimers().

Практические сценарии применения

  • Компоненты с асинхронными API-запросами (axios, fetch)
  • Методы, возвращающие промисы и обновляющие состояние компонента
  • Обработка ошибок и уведомлений после промисов
  • Тестирование событий, инициирующих цепочку асинхронных действий

flushPromises() является стандартным инструментом для обеспечения корректного и надежного тестирования асинхронного поведения компонентов Vue, предотвращая ошибки, связанные с преждевременной проверкой состояния или DOM.