При тестировании компонентов Vue критически важно правильно управлять их жизненным циклом. Жизненный цикл компонента включает создание, монтирование, обновление и уничтожение экземпляра компонента. Некорректная работа с этими этапами может привести к ложноположительным или ложноотрицательным результатам тестов. Vue Test Utils предоставляет набор инструментов для точного контроля жизненного цикла.
Основной метод для создания экземпляра компонента в тестах —
mount. Он принимает компонент и опции, включая
props, slots и global:
import { mount } from '@vue/test-utils'
import MyComponent from '@/components/MyComponent.vue'
const wrapper = mount(MyComponent, {
props: { title: 'Тестовый заголовок' },
slots: { default: '<p>Содержимое слота</p>' }
})
Ключевой момент: при использовании mount компонент
монтируется в виртуальный DOM, что позволяет
тестировать его полностью, включая дочерние компоненты и реактивные
эффекты. Для более лёгкого тестирования с ограниченной глубиной
используется shallowMount, который заменяет дочерние
компоненты заглушками.
Vue Test Utils обеспечивает автоматический вызов следующих хуков:
beforeCreatecreatedbeforeMountmountedbeforeUpdateupdatedbeforeUnmountunmountedПосле монтирования компонента в тесте хуки
created и mounted уже выполнены, что
позволяет проверять состояние компонента и поведение реактивных
данных.
Пример проверки эффекта mounted:
import { mount } from '@vue/test-utils'
import Counter from '@/components/Counter.vue'
const wrapper = mount(Counter)
expect(wrapper.vm.count).toBe(0) // Значение установлено при mounted
Vue использует асинхронный механизм обновления реактивных данных, что требует использования вспомогательных функций для синхронизации тестов с DOM:
nextTick() — дожидается завершения всех текущих
обновлений DOM.flushPromises() — ожидает выполнения всех обещаний,
полезно при работе с API или асинхронными эффектами.Пример:
import { mount } from '@vue/test-utils'
import { nextTick } from 'vue'
import AsyncComponent from '@/components/AsyncComponent.vue'
const wrapper = mount(AsyncComponent)
wrapper.vm.loadData() // Метод, который обновляет данные асинхронно
await nextTick() // Дожидаемся обновления DOM
expect(wrapper.text()).toContain('Данные загружены')
Для освобождения ресурсов и предотвращения утечек памяти важно
корректно размонтировать компонент после теста. Vue Test Utils
предоставляет метод unmount:
wrapper.unmount()
После вызова unmount выполняются хуки
beforeUnmount и unmounted, что позволяет
проверять корректное очищение таймеров, подписок и сторонних
эффектов.
В сочетании с Jest полезно использовать встроенные хуки для инициализации и очистки тестовых данных:
beforeEach() — выполняется перед каждым тестом.afterEach() — выполняется после каждого теста.Пример:
let wrapper
beforeEach(() => {
wrapper = mount(MyComponent)
})
afterEach(() => {
wrapper.unmount()
})
test('проверка начального состояния', () => {
expect(wrapper.text()).toContain('Начальное значение')
})
Такой подход гарантирует, что каждый тест работает с чистым экземпляром компонента, исключая побочные эффекты от предыдущих тестов.
Vue Test Utils позволяет изменять пропсы и данные после монтирования, что активирует обновления компонента:
await wrapper.setProps({ title: 'Новый заголовок' })
await wrapper.setData({ count: 5 })
Каждый вызов автоматически инициирует реактивное обновление и
соответствующие хуки жизненного цикла (beforeUpdate,
updated), что позволяет проверять реакцию компонента на
изменения.
Для компонентов с вложенными детьми важно учитывать глубину монтирования:
mount — монтирует полностью, включая всех детей.shallowMount — заменяет дочерние компоненты заглушками,
предотвращая вызов их mounted и updated.Пример:
import { shallowMount } from '@vue/test-utils'
import Parent from '@/components/Parent.vue'
const wrapper = shallowMount(Parent)
expect(wrapper.findComponent({ name: 'Child' }).exists()).toBe(true)
Использование shallowMount ускоряет тесты и снижает
вероятность ложных срабатываний, если поведение дочернего компонента не
критично для теста.
Для сложных компонентов можно мокировать хуки жизненного цикла с помощью Jest:
jest.spyOn(MyComponent, 'mounted')
mount(MyComponent)
expect(MyComponent.mounted).toHaveBeenCalled()
Такой подход позволяет точно проверять, когда и сколько раз вызываются хуки, особенно при повторном рендеринге или асинхронных обновлениях.
nextTick и flushPromises для
синхронизации асинхронных обновлений.mount и shallowMount в
зависимости от необходимости тестирования дочерних компонентов.beforeEach и
afterEach) для изоляции тестов и контроля состояния
компонентов.Такой подход обеспечивает стабильность тестов и точное воспроизведение поведения компонентов Vue в условиях различных сценариев жизненного цикла.