Триггер кастомных событий

В Vue.js компоненты часто взаимодействуют между собой через кастомные события. При тестировании компонентов важно уметь эмулировать эти события и проверять, как компонент реагирует на них. Библиотека Vue Test Utils предоставляет мощные средства для работы с событиями, включая методы trigger, emit и возможности проверки вызова событий.


Основы кастомных событий

В Vue компонент может генерировать событие с помощью метода this.$emit. Событие имеет название и может передавать аргументы:

export default {
  methods: {
    sendMessage() {
      this.$emit('message-sent', 'Hello, Vue!');
    }
  }
}

В тестах необходимо проверить, что событие было вызвано и переданы корректные данные.


Метод trigger для событий DOM

Метод trigger используется для эмуляции DOM-событий на элементе компонента. Он принимает название события и объект с параметрами события:

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

const wrapper = mount(ButtonComponent);

// Эмулируем клик по кнопке
await wrapper.find('button').trigger('click');

trigger автоматически инициирует события на уровне DOM, а если компонент внутри обработчика использует $emit, событие будет вызвано.


Проверка эмита событий

Vue Test Utils предоставляет метод emitted(), который возвращает объект с событиями, сгенерированными компонентом:

const wrapper = mount(ButtonComponent);

// Триггер клика
await wrapper.find('button').trigger('click');

// Проверка вызова события
expect(wrapper.emitted()['message-sent']).toBeTruthy();

// Проверка количества вызовов
expect(wrapper.emitted()['message-sent'].length).toBe(1);

// Проверка переданных аргументов
expect(wrapper.emitted()['message-sent'][0]).toEqual(['Hello, Vue!']);

Ключевые моменты:

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

Эмуляция пользовательских событий

Иногда необходимо эмулировать событие, исходящее от дочернего компонента, чтобы проверить реакцию родителя:

const Child = {
  template: '<button @click="$emit(\'child-click\', 42)">Click</button>'
};

const Parent = {
  components: { Child },
  template: '<Child @child-click="handleClick"/>',
  methods: {
    handleClick(value) {
      this.$emit('parent-receive', value);
    }
  }
};

const wrapper = mount(Parent);

// Эмулируем событие на дочернем компоненте
await wrapper.findComponent(Child).vm.$emit('child-click', 42);

// Проверка реакции родителя
expect(wrapper.emitted()['parent-receive'][0]).toEqual([42]);

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

  • Использование vm.$emit позволяет напрямую триггерить событие компонента.
  • findComponent обеспечивает поиск вложенного компонента внутри тестируемого компонента.

Параметры события

trigger и vm.$emit поддерживают передачу параметров события, включая объект события для DOM:

await wrapper.find('input').trigger('input', {
  target: { value: 'Vue Test' }
});

expect(wrapper.emitted().input[0]).toEqual(['Vue Test']);

Таким образом, можно имитировать ввод текста, фокус, нажатие клавиш и другие пользовательские действия.


Асинхронные события

Многие события могут вызывать асинхронные действия в компоненте (например, обновление состояния через nextTick):

import { nextTick } from 'vue';

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

expect(wrapper.emitted()['message-sent']).toBeTruthy();

Использование await nextTick() гарантирует, что все реактивные изменения завершены перед проверкой событий.


Сочетание нескольких событий

Тестирование сложных компонентов требует проверки последовательности событий:

await wrapper.find('button').trigger('click');
await wrapper.find('input').trigger('input', { target: { value: 'Test' } });

expect(wrapper.emitted()['message-sent'][0]).toEqual(['Click']);
expect(wrapper.emitted().input[0]).toEqual(['Test']);

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


Рекомендации по использованию

  • trigger подходит для DOM-событий (click, input, focus и т.д.).

  • vm.$emit удобен для кастомных событий компонентов.

  • Использовать wrapper.emitted() для проверки:

    • наличия события
    • количества вызовов
    • переданных аргументов
  • Для асинхронных реакций использовать await nextTick().


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