Проверка испущенных событий (emitted)

В Vue-компонентах события ($emit) играют ключевую роль для коммуникации между дочерними и родительскими компонентами. Vue Test Utils предоставляет удобные инструменты для проверки того, какие события были испущены, с какими аргументами и сколько раз. Это позволяет создавать надёжные unit-тесты, контролирующие поведение компонентов.


Основные методы

wrapper.emitted() — центральный метод для проверки событий. Он возвращает объект, где ключи — имена событий, а значения — массив массивов с аргументами каждого вызова события.

import { mount } from '@vue/test-utils';
import MyButton from '@/components/MyButton.vue';

const wrapper = mount(MyButton);

wrapper.vm.$emit('click', 123);

console.log(wrapper.emitted());
// Вывод:
// {
//   click: [[123]]
// }

Особенности:

  • Если событие не испущено, ключ в объекте отсутствует.
  • Каждое событие хранит массив вызовов: каждый вызов — это массив аргументов.

Проверка конкретного события

Для проверки, было ли событие испущено хотя бы один раз, достаточно проверить наличие ключа:

expect(wrapper.emitted().click).toBeTruthy();

Для проверки количества вызовов:

expect(wrapper.emitted().click.length).toBe(2);

Проверка аргументов конкретного вызова:

expect(wrapper.emitted().click[0]).toEqual([123]);
expect(wrapper.emitted().click[1]).toEqual([456]);

Важно: Индексация начинается с нуля, первый вызов события всегда в [0].


Использование .emittedByOrder()

Vue Test Utils позволяет проверять события в порядке их испускания через метод emittedByOrder(). Это удобно, когда важен последовательный вызов нескольких событий.

wrapper.vm.$emit('first', 'a');
wrapper.vm.$emit('second', 'b');

const emittedOrder = wrapper.emittedByOrder();
console.log(emittedOrder);
// [
//   { name: 'first', args: ['a'] },
//   { name: 'second', args: ['b'] }
// ]

Такой подход облегчает проверку сложной логики компонентов с цепочками событий.


Проверка события после взаимодействия

События обычно испускаются в ответ на пользовательские действия. Vue Test Utils позволяет тестировать это через методы взаимодействия с компонентом.

const wrapper = mount(MyButton);

await wrapper.find('button').trigger('click');

expect(wrapper.emitted().click).toBeTruthy();
expect(wrapper.emitted().click[0]).toEqual([/* ожидаемые аргументы */]);

Особенности:

  • Метод trigger асинхронный для событий, влияющих на реактивное состояние.
  • После await можно безопасно проверять испущенные события.

Проверка пользовательских аргументов и сложных объектов

Если событие испускается с объектом или массивом, важно использовать глубокое сравнение через toEqual:

wrapper.vm.$emit('update', { id: 1, value: 'test' });

expect(wrapper.emitted().update[0]).toEqual([{ id: 1, value: 'test' }]);

Нельзя использовать toBe, так как он проверяет строгое равенство ссылок, а не содержимое объектов.


Сочетание с Jest матчерами

Vue Test Utils прекрасно интегрируется с Jest, что позволяет писать выразительные проверки:

expect(wrapper.emitted().submit).toHaveLength(1);
expect(wrapper.emitted().submit[0]).toEqual([{ name: 'John' }]);
expect(wrapper.emitted().cancel).toBeUndefined();
  • toHaveLength проверяет количество вызовов события.
  • toBeUndefined проверяет отсутствие события.

Такой синтаксис делает тесты компактными и читаемыми.


Практическая стратегия тестирования событий

  1. Проверка испускания события при определённом действии.
  2. Проверка количества вызовов.
  3. Проверка аргументов каждого вызова.
  4. Проверка порядка испускания при нескольких событиях.
  5. Проверка отсутствия неожиданных событий.

Эта последовательность позволяет убедиться, что компонент не только испускает события, но и делает это корректно, в правильном порядке и с правильными данными.


Использование TypeScript с emitted

При работе с TypeScript можно уточнять типы аргументов для события:

interface UpdateEvent {
  id: number;
  value: string;
}

const wrapper = mount<MyComponent>();

wrapper.vm.$emit('update', { id: 1, value: 'test' } as UpdateEvent);

const emitted = wrapper.emitted().update as UpdateEvent[][];
expect(emitted[0][0].id).toBe(1);

Такой подход повышает надёжность тестов и позволяет TypeScript проверять корректность данных.


Поддержка v-model событий

В Vue 3 v-model транслируется в событие update:modelValue. Проверка его испускания не отличается от обычных событий:

const wrapper = mount(MyInput);

await wrapper.find('input').setValue('Hello');

expect(wrapper.emitted()['update:modelValue'][0]).toEqual(['Hello']);

Методика идентична проверке стандартных событий, что упрощает тестирование двусторонней привязки данных.


Эти подходы формируют полноценный арсенал для проверки событий в компонентах Vue с помощью Vue Test Utils, обеспечивая точность, читаемость и надёжность unit-тестов.