How to test eventHub or eventBus with Jest and VueJS

November 15, 2019

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.

Don;t forget to subscribe for more tips and gotchas in our newsletter below.