Testing Emitted Events

As applications grow larger, the number of components grows as well. When these components need to share data, child components can emit an event, and the parent component responds.

vue-test-utils provides an emitted API which allows us to make assertions on emitted events. The documentation for emitted is found here.

The source code for the test described on this page can be found here.

Write a Component and Test

Let's build a simple component. Create an <Emitter> component, and add the following code.

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

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

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

<style scoped>
</style>

Add a test called emitEvent:

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

describe("Emitter", () => {
  it("emits an event with two arguments", () => {
    const wrapper = shallowMount(Emitter)

    wrapper.vm.emitEvent()

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

Using the emitted API provided by vue-test-utils, we can easily see the emitted events.

Run the test with yarn test:unit.

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

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

emitted syntax

emitted returns an object. The emitted events are saved as properties on the object. You can inspect the events using emitted().[event]:

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

Let's try calling emitEvent twice.

it("emits an event with two arguments", () => {
  const wrapper = shallowMount(Emitter)

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

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

Run the test with yarn test:unit:

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

emitted().emitEvent returns an array. The first instance of emitEvent is accessible using with emitted().emitEvent[0]. The arguments are accessible using a similar syntax, emitted().emitEvent[0][0] and so forth.

Let's make an actual assertion against the emitted event.

it("emits an event with two arguments", () => {
  const wrapper = shallowMount(Emitter)

  wrapper.vm.emitEvent()

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

The test passes.

Testing events without mounting the component

Some times you might want to test emitted events without actually mounting the component. You can do this by using call. Let's write another test.

it("emits an event without mounting the component", () => {
  const events = {}
  const $emit = (event, ...args) => { events[event] = [...args] }

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

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

Since $emit is just a JavaScript object, you can mock $emit, and by using call to attach it to the this context of emitEvent. By using call, you can call a method without mounting the component.

Using call can be useful in situations where you have some heavy processing in lifecycle methods like created and mounted that you don't want to execute. Since you don't mount the component, the lifecycle methods are never called. It can also be useful when you want to manipulate the this context in a specific manner.

Conclusion

  • the emitted API from vue-test-utils is used to make assertions against emitted events
  • emitted is a method. It returns an object with properties corresponding to the emitted events
  • each property of emitted is an array. You can access each instance of an emitted event by using the [0], [1] array syntax
  • the arguments of emitted events are also saved as arrays, and can accessed using the [0], [1] array syntax
  • $emit can be mocked using call, assertions can be made without rendering the component

The source code for the test described on this page can be found here.

Last Updated: 10/30/2018, 11:55:43 PM