Работа с динамическим контентом — одна из ключевых задач при тестировании компонентов Vue. Динамическое добавление и удаление элементов часто связано с интерактивными списками, формами, таблицами и другими компонентами, где состояние интерфейса изменяется во время работы приложения. Vue Test Utils предоставляет мощные инструменты для имитации таких изменений и проверки корректности рендеринга и поведения компонентов.
Для начала необходимо смонтировать компонент с помощью функции
mount или shallowMount из Vue Test Utils:
import { mount } from '@vue/test-utils'
import DynamicList from '@/components/DynamicList.vue'
const wrapper = mount(DynamicList)
Основные методы для работы с элементами внутри компонента:
wrapper.find(selector) — возвращает первый найденный
элемент по селектору.wrapper.findAll(selector) — возвращает массив всех
найденных элементов.wrapper.setData({ key: value }) — позволяет изменить
реактивные данные компонента.wrapper.vm.$emit(event, payload) — эмулирует
событие.Эти методы служат базой для тестирования динамических операций.
Добавление элемента в компонент часто реализуется через кнопку или
метод, который изменяет реактивное состояние, например массив
items. Тестирование должно проверять как изменение
состояния, так и корректный рендер нового элемента.
Пример компонента:
<template>
<div>
<ul>
<li v-for="item in items" :key="item">{{ item }}</li>
</ul>
<button @click="addItem">Добавить элемент</button>
</div>
</template>
<script>
export default {
data() {
return {
items: []
}
},
methods: {
addItem() {
this.items.push(`Элемент ${this.items.length + 1}`)
}
}
}
</script>
Тест для проверки добавления элементов:
test('добавление элемента в список', async () => {
const wrapper = mount(DynamicList)
expect(wrapper.findAll('li').length).toBe(0)
await wrapper.find('button').trigger('click')
expect(wrapper.findAll('li').length).toBe(1)
expect(wrapper.find('li').text()).toBe('Элемент 1')
})
Ключевые моменты:
await при trigger('click')
важно для корректного ожидания обновления DOM.wrapper.findAll('li') позволяет проверять текущее
состояние списка после добавления.Удаление элементов реализуется аналогично, но требует передачи индекса или идентификатора элемента. Важно тестировать как состояние данных, так и правильность рендеринга после удаления.
Пример расширенного компонента:
<template>
<div>
<ul>
<li v-for="(item, index) in items" :key="item">
{{ item }}
<button class="remove" @click="removeItem(index)">Удалить</button>
</li>
</ul>
<button @click="addItem">Добавить элемент</button>
</div>
</template>
<script>
export default {
data() {
return {
items: []
}
},
methods: {
addItem() {
this.items.push(`Элемент ${this.items.length + 1}`)
},
removeItem(index) {
this.items.splice(index, 1)
}
}
}
</script>
Тест для удаления элементов:
test('удаление элемента из списка', async () => {
const wrapper = mount(DynamicList)
await wrapper.find('button').trigger('click') // добавляем элемент
await wrapper.find('button').trigger('click') // добавляем второй элемент
expect(wrapper.findAll('li').length).toBe(2)
await wrapper.findAll('.remove')[0].trigger('click')
const items = wrapper.findAll('li')
expect(items.length).toBe(1)
expect(items[0].text()).toContain('Элемент 2')
})
Особенности тестирования удаления:
v-for с ключами позволяет Vue правильно обновлять DOM
при удалении..toContain или .text()
позволяет убедиться, что удалён правильный элемент.При динамических операциях иногда используются асинхронные методы или
эффекты (например, при работе с API). В таких случаях требуется
использовать await Vue.nextTick() или встроенные
возможности await wrapper.vm.$nextTick() для ожидания
обновления DOM перед проверкой состояния элементов:
import { nextTick } from 'vue'
test('добавление элемента с nextTick', async () => {
const wrapper = mount(DynamicList)
wrapper.vm.addItem()
await nextTick()
expect(wrapper.findAll('li').length).toBe(1)
})
Для динамических списков важно тестировать не только изменение состояния, но и правильность взаимодействия с пользователем:
trigger('click').@click или
$emit.setValue для полей ввода перед
добавлением элементов.Пример добавления элемента через поле ввода:
<input v-model="newItem" />
<button @click="addItem">Добавить</button>
Тестирование:
await wrapper.find('input').setValue('Новый элемент')
await wrapper.find('button').trigger('click')
expect(wrapper.findAll('li')[0].text()).toBe('Новый элемент')
wrapper.vm.items), так
и отображение в DOM (wrapper.findAll('li')).v-for с уникальными ключами для избежания
проблем с виртуальным DOM при динамических изменениях.await с
nextTick или trigger.Если элементы списка — это отдельные дочерние компоненты, важно:
findComponent или
findAllComponents для поиска дочерних компонентов.Пример:
expect(wrapper.findAllComponents(ItemComponent).length).toBe(3)
Такой подход гарантирует, что динамическое добавление и удаление элементов полностью контролируется как с точки зрения Vue, так и с точки зрения рендеринга в DOM.