Vue Test Utils (VTU) — ключевой инструмент для юнит-тестирования компонентов Vue.js. С развитием Vue 3 и релиза Vue Test Utils версии 2 произошло несколько значительных изменений в API, которые влияют на подходы к тестированию, синтаксис вызовов и возможности работы с компонентами. Рассмотрим основные изменения подробно.
mount и shallowMountВ VTU v1 для Vue 2 существовали методы mount и
shallowMount с простым набором опций. В версии 2 структура
опций изменилась, появились новые возможности:
Ключевые изменения:
global объект В Vue Test Utils v2
большинство глобальных конфигураций (плагины, компоненты, директивы,
миксины) теперь передаются через объект global:
import { mount } from '@vue/test-utils'
import MyComponent from '@/components/MyComponent.vue'
import Vuex from 'vuex'
const wrapper = mount(MyComponent, {
global: {
plugins: [Vuex],
components: {
CustomButton: MyButton
},
directives: {
focus: {
mounted(el) { el.focus() }
}
}
}
})stubs внутри global
Ранее stubs передавались напрямую в опции
mount. Сейчас рекомендуется помещать их внутрь
global для унифицированного доступа:
const wrapper = mount(MyComponent, {
global: {
stubs: ['router-link']
}
})mocks Имитации глобальных объектов,
таких как $router и $route, теперь тоже
находятся в global.mocks:
const wrapper = mount(MyComponent, {
global: {
mocks: {
$router: { push: jest.fn() },
$route: { params: { id: 1 } }
}
}
})API работы с событиями в версии 2 стало более строгим:
trigger Метод trigger
теперь возвращает промис, так как многие события могут быть асинхронными
с Vue 3. Для правильного ожидания изменений в DOM необходимо
использовать await:
await wrapper.find('button').trigger('click')События компонента emitted()
продолжает работать, но с улучшенной типизацией:
wrapper.vm.$emit('submit', { name: 'test' })
expect(wrapper.emitted().submit[0]).toEqual([{ name: 'test' }])Пропсы В v2 пропсы можно передавать напрямую как объект, но теперь рекомендуется строго типизировать для Vue 3:
const wrapper = mount(MyComponent, {
props: { title: 'Пример' }
})Слоты Синтаксис слотов унифицирован с Vue 3:
const wrapper = mount(MyComponent, {
slots: {
default: '<span>Текст слота</span>',
header: '<h1>Заголовок</h1>'
}
})Scoped слоты Поддержка функциональных слотов теперь полностью через функции:
const wrapper = mount(MyComponent, {
slots: {
default: ({ text }) => `<div>${text}</div>`
}
})find и findAll Методы
остались, но теперь возвращают объект DOMWrapper с
расширенным API, полностью совместимым с Vue 3 реактивностью:
const button = wrapper.find('button')
expect(button.exists()).toBe(true)findComponent и
findAllComponents Для поиска дочерних компонентов
теперь рекомендуется использовать именно эти методы, а не селекторы по
классу или тегу:
const childWrapper = wrapper.findComponent({ name: 'ChildComponent' })Vue 3 активно использует асинхронные компоненты и
Suspense. VTU v2 обеспечивает поддержку тестирования таких
компонентов:
Асинхронные компоненты:
import AsyncComp from '@/components/AsyncComp.vue'
const wrapper = mount(AsyncComp)
await flushPromises() // ожидание рендеринга асинхронного компонентаflushPromises Метод из VTU или
сторонней утилиты для ожидания завершения всех промисов в компоненте,
необходим при асинхронном рендеринге.
vm и реактивные данные В VTU v2
wrapper.vm предоставляет доступ к реактивным свойствам
компонента, но любые изменения нужно сопровождать
await nextTick():
wrapper.vm.count++
await wrapper.vm.$nextTick()
expect(wrapper.text()).toContain('1')Реактивные props и watch Изменение пропсов через
setProps стало асинхронным:
await wrapper.setProps({ title: 'Новый заголовок' })
expect(wrapper.text()).toContain('Новый заголовок')Некоторые утилиты из VTU v1 были удалены или изменены:
wrapper.html() и
wrapper.text() остались без изменений, но
возвращают актуальный DOM после асинхронных обновлений.wrapper.setData() теперь работает
только с реактивными свойствами Vue 3 и должна использоваться
аккуратно.setComputed и destroy
были удалены.| VTU v1 (Vue 2) | VTU v2 (Vue 3) |
|---|---|
mount(Component, options) |
mount(Component, { global: { ... } }) |
shallowMount(Component) |
shallowMount(Component, { global: { ... } }) |
wrapper.setProps() |
асинхронный, требует await |
wrapper.trigger() |
асинхронный, требует await |
findComponent({ ref }) |
сохраняется, поддержка Composition API |
setData() |
работает только с реактивными свойствами |
Изменения в API Vue Test Utils v2 обеспечивают полную совместимость с
Vue 3 и позволяют более строго и предсказуемо тестировать компоненты,
особенно с учетом реактивной природы данных, асинхронных компонентов и
глобальной конфигурации. Правильное использование новых опций
global, асинхронных методов и строгой типизации пропсов
становится ключевым при построении надежных тестов.