Это руководство было написано для Vue.js 2 и Vue Test Utils v1.

Версия для Vue.js 3 здесь.

# Тестирования пользовательских событий

С ростом приложения растёт количество компонентов. Когда им нужно общаться между собой, дочерний компонент может породить событие, а родитель ответить на него.

vue-test-utils предоставляет emitted API, который позволит нам сделать проверку на пользовательские события. Документацию для emitted можно найти здесь.

Исходный код для тестов на этой странице можно взять тут.

# Написание компонента и теста к нему

Давайте сделаем простой компонент. Назовём его <Emitter> и добавим следующий код:

<template>
  <div>
  </div>
</template>

<script>
  export default {
    name: "Emitter",

    methods: { 
      emitEvent() {
        this.$emit("myEvent", "name", "password")
      }
    }
  }
</script>

Тест назовём emitEvent:

import Emitter from "@/components/Emitter.vue"
import { mount } from "@vue/test-utils"

describe("Emitter.vue", () => {
  it("Порождает событие с двумя аргументами", () => {
    const wrapper = mount(Emitter)

    wrapper.vm.emitEvent()

    console.log(wrapper.emitted())
  })
})

Используя emitted API, предоставленный нам vue-test-utils, мы можем с лёгкостью посмотреть все порождённые события.

Запустим тест, написав yarn test:unit.

PASS  tests/unit/Emitter.spec.js
● Console

  console.log tests/unit/Emitter.spec.js:10
    { myEvent: [ [ 'name', 'password' ] ] }

# Синтаксис emitted

emitted возвращает объект. Порождённые события сохраняются, как свойства объекта. Вы можете проверять события, используя emitted().[event]:

emitted().myEvent //=>  [ [ 'name', 'password' ] ]

Давайте попробуем вызвать emitEvent дважды:

it("Порождает событие с двумя аргументами", () => {
  const wrapper = mount(Emitter)

  wrapper.vm.emitEvent()
  wrapper.vm.emitEvent()

  console.log(wrapper.emitted().myEvent)
})

Запустим тест, написав yarn test:unit.

console.log tests/unit/Emitter.spec.js:11
  [ [ 'name', 'password' ], [ 'name', 'password' ] ]

emitted().emitEvent возвращает массив. Первый экземпляр emitEvent можно достать через emitted().emitEvent[0]. Аргументы получают похожим синтаксисом: emitted().emitEvent[0][0] и так далее.

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

it("Порождает событие с двумя аргументами", () => {
  const wrapper = mount(Emitter)

  wrapper.vm.emitEvent()

  expect(wrapper.emitted().myEvent[0]).toEqual(["name", "password"])
})

Тест проходит проверку.

# Тестирование событий без монтирования компонента

Иногда может потребоваться протестировать пользовательские события без монтирования компонента. Этого можно достичь, используя call. Давайте напишем ещё один тест.

it("Порождает событие без монтирования компонента", () => {
  const events = {}
  const $emit = (event, ...args) => { events[event] = [...args] }

  Emitter.methods.emitEvent.call({ $emit })

  expect(events.myEvent).toEqual(["name", "password"])
})

Так как $emit – обычный JavaScript объект, мы может замокать $emit и использовать call, чтобы прикрепить его к контексту this из emitEvent. Используя call, вы также можете вызывать методы без монтирования компонента.

Использовать call может быть полезно в ситуациях, где есть несколько тяжёлых функций в хуках жизненного цикла created или mounted, и вы не хотите их выполнять. Так как вы не монтируете компонент, функции из хуков никогда не выполнятся. Также call полезен при манипулировании контекстом this.

# Заключение

  • emitted API из vue-test-utils используется, чтобы проверять пользовательские события
  • emitted - это метод возвращающий объект, в свойствах которого находятся порожденные события
  • каждое свойство из emitted является массивом. Чтобы достать экземпляр пользовательских событий, можно использовать синтаксис массивов [0], [1]
  • аргументы для пользовательских событий также сохраняются в виде массивов, которые можно взять, используя [0], [1].
  • $emit можно замокать, используя call. Проверки можно делать без монтирования компонента

Исходный код для тестов на этой странице можно взять тут.