Vue Testing: Testing Router Hooks

Chris Washington
2 min readDec 5, 2019

--

Intro

It isn’t always obvious how to go about testing certain aspects of your front end code. This is especially true when it comes to the Vue router. This is even more true when it comes to testing the execution of your various router hooks.

Background

beforeEach , afterEach , and beforeResolve each behave similarly in its underlying code.

If you take a look at the Vue router object you will see that for each of the respective router hooks it is making a call to the method registerHook and passing a hook and then the registered function to be appended/pushed onto the hook array.

If you clicked on the link above and investigated the file you would have found the following:

beforeEach (fn: Function): Function {
return registerHook(this.beforeHooks, fn)
}
beforeResolve (fn: Function): Function {
return registerHook(this.resolveHooks, fn)
}
afterEach (fn: Function): Function {
return registerHook(this.afterHooks, fn)
}

This gives us some insight into how we can easily unit test these hooks. The vue-router package comes with types that have been defined and on these types they do not expose the variables beforeHooks , resolveHooks , or afterHook . Thankfully for our purposes they left each of these as public variables on the object.

Let’s Unit Test

Take the following router.js file at the root of a Vue application folder:

// router.jsimport Vue from 'vue';import VueRouter from 'vue-router';import Home from '@/Home.vue';import someService from '@/services/some-service';Vue.use(VueRouter);export const routes = {
mode: 'history',
routes: [{
path: '/',
name: 'home',
component: Home,
redirect: { name: 'controls-dashboard' }
}]
};
const router = new VueRouter(routes);router.beforeEach((to, from, next) => {
someService(to, from, next);
});
export default router;

The above router has some code that we want to test inside of the beforeEachthat will be called when invoked: someService .

To be able to unit test whether someService gets called properly, we have to access the beforeHooks variable:

import router, { routes } from '@/router';import someService from '@/services/some-service';//using jest to mock
jest.mock('@/services/some-service');
describe('when router.beforeEach is called', () => {
it('then someService is called', () => {
const to = jest.fn();
const from = jest.fn();
const next = jest.fn();
router.beforeHooks.forEach((hook) => {
hook(to, from, next);
});

expect(someService).toHaveBeenCalledWith(to, from, next);
});
});

The reason we do forEach instead of just referencing the zeroth index, is because you can have multiple beforeEach hooks.

Conclusion

You can do the same for beforeResolve and afterEach as well by iterating over resolveHooks and afterHooks , respectively.

--

--

Chris Washington
Chris Washington

Written by Chris Washington

Chris is a Sr. Lead Software Engineer at Capital One just doing what he loves: creating epic things, and writing about them.

Responses (1)