Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62
Subscribe to my email list now at http://jauyeung.net/subscribe/
With the Vue Test Utils library, we can write and run unit tests for Vue apps easily.
In this article, we’ll look at how to write unit tests with the Vue Test Utils library.
Mocking $route
and $router
We can mock the $route
and $router
objects to inject the Vue Router’s reactive properties into our mounted component.
For instance, we can write:
import { shallowMount } from '@vue/test-utils'
const Component = {
template: `
<div>
<p>{{$route.path}}</p>
</div>
`
}
describe('Component', () => {
it('renders the Component component with the path', async () => {
const $route = {
path: '/some/path'
}
const wrapper = shallowMount(Component, {
mocks: {
$route
}
})
expect(wrapper.text()).toContain('/some/path')
})
})
We have the Component
component that renders the $route.path
value.
We just put that in the mocks
property so that it’ll be set with the given value when we mount the component.
Testing Vuex in Components
We can test components that depends on Vuex.
For example, if we have a Vue app that has the following code:
main.js
import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex'
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
Vue.config.productionTip = false
new Vue({
store,
render: h => h(App),
}).$mount('#app')
App.vue
<template>
<div id="app">
<button @click="$store.dispatch('increment')">add</button>
<p>{{count}}</p>
</div>
</template>
<script>
export default {
name: "App",
computed: {
count() {
return this.$store.state.count;
},
},
};
</script>
Then we can test the code by writing:
example.spec.js
import { shallowMount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import App from '@/App'
const localVue = createLocalVue()
localVue.use(Vuex)
describe('App.vue', () => {
let actions
let store
beforeEach(() => {
actions = {
increment: jest.fn(),
}
store = new Vuex.Store({
actions
})
})
it('dispatches "increment" action when button is clicked', async () => {
const wrapper = shallowMount(App, { store, localVue })
const button = wrapper.find('button')
await button.trigger('click')
expect(actions.increment).toHaveBeenCalled()
})
})
Once again, we call createLocalVue
to create a local Vue instance we use for testing.
Then we have a beforeEach
callback to set up the store and inject it into our app.
We inject the mocked store and the localVue
object.
Then we get the button and trigger the click
event on it.
And finally, we check that the increment
action has been triggered after clicking the button.
Mocking Getters
Similarly, we can mock getters in our tests.
Given that we have the following code:
main.js
import Vue from 'vue'
import App from './App.vue'
import Vuex from 'vuex'
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
},
actions: {
increment(context) {
context.commit('increment')
}
},
getters: {
count(state) {
return state.count;
}
}
})
Vue.config.productionTip = false
new Vue({
store,
render: h => h(App),
}).$mount('#app')
App.vue
<template>
<div id="app">
<button @click="$store.dispatch('increment')">add</button>
<p>{{count}}</p>
</div>
</template>
<script>
import { mapGetters } from "vuex";
export default {
name: "App",
computed: {
...mapGetters(['count'])
},
};
</script>
Then to test our code, we write:
import { shallowMount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import App from '@/App'
const localVue = createLocalVue()
localVue.use(Vuex)
describe('App.vue', () => {
let actions
let store
let getters
beforeEach(() => {
getters = {
count: () => 2,
}
actions = {
increment: jest.fn(),
}
store = new Vuex.Store({
actions,
getters
})
})
it('dispatches "increment" action when button is clicked', () => {
const wrapper = shallowMount(App, { store, localVue })
expect(+wrapper.find('p').text()).toBe(getters.count())
})
})
We add the mock getter into out mock store
object.
Then we get the p
element’s text and sees if it matches what’s returned in the mocked getter.
Conclusion
We can mock Vuex and Vue Router in our tests so that our components can be tested in isolation.