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 Injections
We can mock injected reactive properties by passing them all in the mocks
property when we mount our component.
For example, we can write:
import { mount } from '@vue/test-utils'
const Foo = {
template: `
<div>
<p>{{$route.path}}</p>
</div>
`,
}
const $route = {
path: '/foo',
}
test('should render the path', () => {
const wrapper = mount(Foo, {
mocks: {
$route
}
})
expect(wrapper.text()).toContain('/foo')
})
We just set the $route
property to the $route
object in the mocks
object then we should see it rendered.
Stubbing Components
We can stub global components by writing using the stubs
property:
import { mount } from '@vue/test-utils'
const Foo = {
template: `
<div>
<child-component></child-component>
</div>
`,
}
test('should render child-component', () => {
const wrapper = mount(Foo, {
stubs: ['child-component']
})
expect(wrapper.find('child-component')).toBeTruthy()
})
We have the child-component
in Foo
which we didn’t register, so we can stub it by using the stubs
property to stub it with an empty component.
Testing Key, Mouse, and Other DOM Events
We can trigger events on component with the trigger
method.
For example, we can write:
import { mount } from '@vue/test-utils'
const MyButton = {
template: `
<button @click='count++'>
{{count}}
</button>
`,
data() {
return {
count: 0
}
}
}
test('shows latest count when button is clicked', async () => {
const wrapper = mount(MyButton)
await wrapper.trigger('click')
expect(wrapper.text()).toContain('1');
})
We mount the MyButton
component and call trigger
on the returned component wrapper.
Then we can check the latest value of count
with the text
method.
For example, we can write:
import { mount } from '@vue/test-utils'
const MyButton = {
template: `
<div>
<button @click='count++'>
add
</button>
<p>{{count}}</p>
</div>
`,
data() {
return {
count: 0
}
}
}
test('shows latest count when button is clicked', async () => {
const wrapper = mount(MyButton)
await wrapper.find('button').trigger('click')
expect(wrapper.find('p').text()).toContain('1');
})
to create the MyButton
component with the add button.
It updated the count
when we click it.
To test it, we call find
to find the button. Then we call trigger
to trigger the click
event.
Then we call find
with the 'p'
selector to check the content of the p element.
We can check if a method is called when we trigger an event on an element.
For example, we can write:
import { mount } from '@vue/test-utils'
const Foo = {
template: `
<div>
<button class="yes" @click="callYes">Yes</button>
<button class="no" @click="callNo">No</button>
</div>
`,
props: {
callMe: {
type: Function
}
},
methods: {
callYes() {
this.callMe('yes')
},
callNo() {
this.callMe('no')
}
}
}
test('should call callMe with the right arguments when buttons are clicked', async () => {
const spy = jest.fn();
const wrapper = mount(Foo, {
propsData: {
callMe: spy
}
})
await wrapper.find('button.yes').trigger('click')
expect(spy).toHaveBeenCalledWith('yes');
await wrapper.find('button.no').trigger('click')
expect(spy).toHaveBeenCalledWith('no');
})
We have the Foo
component that takes a callMe
function as a prop.
Then to write our test, we create a spy of the callMe
function by calling jest.fn()
.
Next, we pass that in as a prop with we mount Foo
.
Finally, we call trigger
to trigger clicks on the buttons and check the rendered results.
toHaveBeenCalledWith
takes the arguments of the function we’re expecting.
Conclusion
We can mock various items in our components with Jest and Vue Test Utils.