How to test eventHub or eventBus with Jest and VueJS

May 2, 2020 by Jose Garrido

Recently I had the opportunity to start integrating unit tests in some of my Vue components. The problem is I often use $eventHubs as a way to communicate between components in mid-sized applications. So for example if a component wants to notify the header of the app that something happened I normally use an eventHubto make that communication.

In my main.js file I initialize the $eventHub like this:

Vue.prototype.$eventHub = new Vue();

Then in the component where I want to emit the event I do this:

methods: {
  notifyHeader(){
    this.$eventHub.$emit('new_message');
  }
}

And in the component where I want to receive the events I do something like this:

created(){
  this.$eventHub.$on('new_message', () => {
    console.log('received a new message');
    // this.handleMessageMethod();
  });
}

That's how I personally go about communicating events between Vue components and it has given me great results over time. The problem came when I wanted to use Jest to test the components that were emmiting or receiving these events. Upon running npm run test I would receive the following error:

TypeError: Cannot read property '$on' of undefined

      58 |         },
      59 |         created(){
    > 60 |             this.$eventHub.$on('new_message',() => {

How to test an eventHub with VueTestUtils and Jest

To solve this you need to create your test spec file with some considerations in mind:

First, you need to remember that in your Vue code you are creating the eventHub as a variable in your Vue instance Vue.prototype.$eventHub = new Vue(). In order for the test suite to be able to find the hub in the same place we are going to use a localVue instance to replicate the hub in localVue.prototype.$eventHub = createLocalVue().

Second, we are going to use a GlobalPlugins object that will help us initialize the hub correctly on the test suite.

import { mount, createLocalVue } from '@vue/test-utils'
import Vue from 'vue';
import TestComponent from '../../src/TestComponent.vue'

const EventBus = new Vue();
const GlobalPlugins = {
    install(v) {
        // Event bus
        v.prototype.$eventHub = EventBus;
    },
};

const localVue = createLocalVue();
localVue.prototype.$eventHub = createLocalVue();
localVue.use(GlobalPlugins);

describe('TestComponent', () => {
    test('is a Vue instance', () => {
        const wrapper = mount(TestComponent, { localVue })
        expect(wrapper.isVueInstance()).toBeTruthy()
    })

})

And that's it now your test pass with an $eventHub or $eventBus:

> vue-cli-service test:unit

 PASS  tests/unit/_TestComponent.spec.js

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.853s, estimated 2s
Ran all test suites.

Did you like the article? Consider subscribing to the newsletter.

The latest articles and resources, sent directly to your inbox. The best part? It's free.