В тестировании компонентов Vue часто возникает необходимость проверять не только факт генерации событий, но и точное количество их срабатываний. Это важно для компонентов, которые, например, должны реагировать на пользовательские действия строго определённое число раз, предотвращая избыточные вызовы методов или ошибок логики.
Vue Test Utils предоставляет несколько ключевых средств для работы с событиями:
emitted(): возвращает объект, содержащий все события,
сгенерированные компонентом, сгруппированные по имени события.wrapper.trigger(): позволяет программно вызвать событие
DOM, например, клик.toHaveBeenCalledTimes() и
mockImplementation() для проверки вызовов методов и
функций.Предположим, есть компонент CounterButton.vue:
<template>
<button @click="increment">Нажми меня</button>
</template>
<script>
export default {
data() {
return { count: 0 }
},
methods: {
increment() {
this.count++
this.$emit('increment', this.count)
}
}
}
</script>
Для проверки количества срабатываний события increment
можно использовать следующий подход:
import { mount } from '@vue/test-utils'
import CounterButton from '@/components/CounterButton.vue'
test('событие increment срабатывает нужное количество раз', async () => {
const wrapper = mount(CounterButton)
await wrapper.find('button').trigger('click')
await wrapper.find('button').trigger('click')
await wrapper.find('button').trigger('click')
const emittedEvents = wrapper.emitted('increment')
expect(emittedEvents).toHaveLength(3)
})
Ключевой момент: метод
emitted('eventName') возвращает массив, где каждый элемент
— массив аргументов события. Использование toHaveLength()
позволяет проверить точное число срабатываний.
Иногда требуется убедиться, что событие не только сработало нужное количество раз, но и передавало правильные значения:
expect(emittedEvents).toEqual([[1], [2], [3]])
Здесь проверяется, что первый клик передал 1, второй —
2, третий — 3. Такой подход позволяет
обнаруживать ошибки инкрементации и неправильной логики обработки
событий.
Для компонентов, где событие вызывается внутри метода, можно проверять количество вызовов метода, что косвенно подтверждает срабатывания события:
test('метод increment вызывается 3 раза при кликах', async () => {
const wrapper = mount(CounterButton)
const spy = jest.spyOn(wrapper.vm, 'increment')
await wrapper.find('button').trigger('click')
await wrapper.find('button').trigger('click')
await wrapper.find('button').trigger('click')
expect(spy).toHaveBeenCalledTimes(3)
})
Если событие срабатывает после асинхронной операции (например,
API-запроса или setTimeout), необходимо использовать
async/await и nextTick:
<template>
<button @click="delayedEmit">Отложенный клик</button>
</template>
<script>
export default {
methods: {
async delayedEmit() {
await new Promise(resolve => setTimeout(resolve, 50))
this.$emit('delayed', 1)
}
}
}
</script>
Тест:
import { mount } from '@vue/test-utils'
import { nextTick } from 'vue'
import DelayedButton from '@/components/DelayedButton.vue'
test('событие delayed срабатывает 2 раза', async () => {
const wrapper = mount(DelayedButton)
wrapper.find('button').trigger('click')
wrapper.find('button').trigger('click')
await new Promise(resolve => setTimeout(resolve, 60))
await nextTick()
expect(wrapper.emitted('delayed')).toHaveLength(2)
})
Особенность: без await nextTick()
массив событий может быть пустым, так как Vue ещё не завершил обновление
виртуального DOM.
toHaveLength() лучше, чем проверка > 0, так
как исключает скрытые баги.emitted() — для
внешнего поведения компонента.Контроль количества срабатываний событий в Vue Test Utils позволяет
выявлять баги, связанные с избыточной генерацией событий или
неправильной логикой. Комбинация методов emitted(),
trigger() и Jest-спаев обеспечивает полное покрытие
проверок, включая асинхронные сценарии и проверку переданных аргументов.
Такой подход гарантирует надежное тестирование компонентов с
интерактивным поведением.