Vue.js предоставляет мощный механизм для работы с анимациями и
переходами через встроенные компоненты <transition> и
<transition-group>. Тестирование таких элементов
требует понимания того, как Vue Test Utils взаимодействует с DOM и
асинхронными процессами анимации. Важно помнить, что по умолчанию
анимации не выполняются в тестовой среде так, как в браузере, поэтому
методы тестирования должны учитывать виртуальное выполнение
переходов.
<transition> и
<transition-group><transition> используется для
анимации одиночного элемента при его появлении и исчезновении из DOM.
Ключевые моменты для тестирования:
v-enter, v-enter-active, v-leave,
v-leave-active. Тест должен проверять присутствие этих
классов в нужные моменты.before-enter,
enter, after-enter, before-leave,
leave, after-leave. Они могут быть замоканы
через Jest или другой фреймворк, чтобы проверить последовательность
вызовов.<transition-group> используется
для анимации списка элементов. Отличия в тестировании:
key), что
критично для правильной работы анимаций.findAll, позволяют
проверить, какие элементы присутствуют в DOM и какие классы перехода
применяются.В тестовой среде реальная анимация не выполняется, поэтому приходится использовать мокирование функций переходов или асинхронное ожидание событий.
1. Мокирование CSS-анимаций:
import { mount } from '@vue/test-utils'
import MyComponent from '@/components/MyComponent.vue'
jest.mock('vue', () => ({
...jest.requireActual('vue'),
nextTick: (fn) => fn(),
}))
test('проверка классов transition', async () => {
const wrapper = mount(MyComponent)
wrapper.find('button').trigger('click')
await wrapper.vm.$nextTick()
expect(wrapper.find('.element').classes()).toContain('v-enter-active')
})
nextTick используется для ожидания обновления DOM после
изменения состояния.2. Асинхронное тестирование событий:
test('проверка событий transition', async () => {
const beforeEnter = jest.fn()
const afterEnter = jest.fn()
const wrapper = mount(MyComponent, {
props: { beforeEnter, afterEnter }
})
wrapper.setData({ visible: true })
await wrapper.vm.$nextTick()
expect(beforeEnter).toHaveBeenCalled()
await wrapper.vm.$nextTick()
expect(afterEnter).toHaveBeenCalled()
})
$nextTick гарантируют, что все
события анимации успели произойти.1. Анимации списков с
<transition-group>
Для тестов списка элементов важно проверять добавление, удаление и перестановку элементов. Пример:
const wrapper = mount({
template: `
<transition-group name="list" tag="ul">
<li v-for="item in items" :key="item">{{ item }}</li>
</transition-group>
`,
data() {
return { items: ['A', 'B', 'C'] }
}
})
wrapper.setData({ items: ['B', 'C', 'D'] })
await wrapper.vm.$nextTick()
const listItems = wrapper.findAll('li')
expect(listItems.map(li => li.text())).toEqual(['B', 'C', 'D'])
listItems.forEach(li => {
expect(li.classes()).toContain('list-move')
})
list-move.2. Комбинированные анимации
Если компонент использует несколько переходов одновременно (например,
<transition> внутри
<transition-group>), тестирование должно учитывать
последовательность:
v-if.before-* и after-* для
каждого слоя анимации.await wrapper.vm.$nextTick() после
каждого изменения состояния.trigger для имитации
пользовательских событий, вызывающих анимацию.jest.useFakeTimers() для ускорения тестов.await flushPromises() или
$nextTick() для корректного ожидания завершения
анимаций.<transition-group> учитывать
динамические ключи и проверять, что порядок элементов в
DOM соответствует ожиданиям.<Transition> и
<TransitionGroup> стали более предсказуемыми: все
асинхронные хуки возвращают промисы, которые удобно ожидать в
тестах.mount вместо
shallowMount, если требуется тестировать реальные классы
анимации, так как shallowMount не рендерит дочерние
компоненты полностью.