При тестировании Vue-компонентов часто возникает необходимость проверять асинхронное поведение, например, загрузку данных с API или выполнение внутренних промисов. Vue Test Utils предоставляет средства для корректной работы с асинхронностью, позволяя уверенно управлять состоянием компонента после выполнения промисов.
Vue Test Utils использует реальную очередь обновлений Vue, поэтому изменения в реактивных данных не применяются мгновенно. Это особенно важно при работе с промисами:
import { mount } from '@vue/test-utils'
import MyComponent from '@/components/MyComponent.vue'
test('обновление данных после промиса', async () => {
const wrapper = mount(MyComponent)
await wrapper.vm.fetchData() // метод, возвращающий промис
await wrapper.vm.$nextTick()
expect(wrapper.text()).toContain('Данные загружены')
})
Ключевой момент:
await wrapper.vm.$nextTick() гарантирует, что Vue успел
обновить DOM после изменения реактивного состояния.
flushPromisesДля удобного ожидания всех активных промисов можно применять утилиту
flush-promises:
import flushPromises from 'flush-promises'
test('загрузка данных через API', async () => {
const wrapper = mount(MyComponent)
wrapper.vm.loadData() // вызывает промис
await flushPromises()
expect(wrapper.find('.data-item').exists()).toBe(true)
})
flushPromises() позволяет дождаться завершения всех
промисов в текущем цикле событий, исключая необходимость многократного
вызова $nextTick.
Для тестов удобно заменять реальные вызовы API моками:
jest.mock('@/api', () => ({
fetchItems: jest.fn(() => Promise.resolve(['item1', 'item2']))
}))
import { fetchItems } from '@/api'
test('отрисовка списка после fetchItems', async () => {
const wrapper = mount(MyComponent)
await wrapper.vm.loadItems()
await flushPromises()
expect(wrapper.findAll('li')).toHaveLength(2)
expect(fetchItems).toHaveBeenCalled()
})
Особенности:
jest.mock позволяет контролировать возвращаемые
значения и исключить сетевые запросы.await или дождаться с помощью
flushPromises.Компоненты могут эмитировать события после завершения промиса:
test('эмит события после завершения промиса', async () => {
const wrapper = mount(MyComponent)
wrapper.vm.saveData()
await flushPromises()
expect(wrapper.emitted('saved')).toBeTruthy()
})
Эмит событий можно проверять после полного завершения всех асинхронных действий, что предотвращает ложноположительные или неполные проверки.
Если промис зависит от таймеров (setTimeout,
setInterval), важно использовать Jest Fake Timers:
jest.useFakeTimers()
test('обновление данных через setTimeout', async () => {
const wrapper = mount(MyComponent)
wrapper.vm.delayedUpdate()
jest.runAllTimers()
await flushPromises()
expect(wrapper.text()).toContain('Обновлено')
})
Примечание: jest.runAllTimers()
синхронно завершает все таймеры, а flushPromises
гарантирует обработку промисов, созданных внутри таймера.
Vue Test Utils позволяет проверять реактивные данные после промисов:
test('реактивное свойство после промиса', async () => {
const wrapper = mount(MyComponent)
await wrapper.vm.fetchStatus()
await wrapper.vm.$nextTick()
expect(wrapper.vm.status).toBe('loaded')
})
Рекомендация: всегда использовать комбинацию
await и $nextTick или
flushPromises, чтобы избежать состояния гонки между
завершением промиса и обновлением DOM.
$nextTick или
flushPromises — приводит к проверкам до того, как
DOM обновился.Для стабильного тестирования асинхронного поведения рекомендуется:
await.flushPromises для ожидания всех активных
промисов.$nextTick для синхронизации обновлений
Vue.Эти подходы обеспечивают точную проверку состояния компонентов и корректное тестирование сложной логики асинхронных действий.