Table of contents
- Use
await Vue.nextTick()
instead of using a callback insidenextTick()
- Use
await nextTick()
after triggering events - Be aware that using a callback in
nextTick()
will mean errors are not caught - Get emitted events from a component
- Fake an emitted event from a child element
- Get all listeners for a component in Vue Test Utils
- Stub out transitions with Vue Test Utils
- Remember when testing with Vue Router that if you use
createLocalVue
and use the Router on it, the$route
and$router
properties are read-only - Get all Vue props with
wrapper.props()
- If testing on a server and need to test rendered HTML, use
render()
orrenderToString()
- Use
is()
to check the type of a component - Use
find()
with thename
orref
option - Use
createWrapper
to create a wrapper for a mounted Vue instance or HTML element - Suppress Vue warnings by using the
config.silent
option - Retrieve the query selector used with
find()
orfindAll()
- Use
Wrapper
methodattributes()
to get an element attribute list - Use
Wrapper
methodclasses()
to get an element class list - Check if a wrapper contains an element or component with
contains()
- Use
exists()
on aWrapper
orWrapperArray
- Do not use
find()
to search for a component! UsefindComponent()
instead - You can chain
find()
calls - Use
get()
instead offind()
when it must find something - Do not use these deprecated functions on
Wrapper
objects - Use these helper methods to set data on
Wrapper
orWrapperArray
objects - You can call
filter()
onWrapperArray
objects - Use
is()
onWrapperArray
objects to check that every wrapper inside it matches the selector - Vue mounting options:
data
gets merged with existing data - Vue mounting options: supplying a string
stubs
value is deprecated - Vue mounting options:
propsData
- UsepropsData
mounting option to set initial props - Vue mounting options: use the
listeners
attribute to set a component instance's$listeners
object - Vue mounting options: use the
parentComponent
option to set the component to use as a parent.
Vue has an excellent testing package called vue-test-utils.
If you have not yet started testing your Vue applications then I recommend that you check out Vue Test Utils. It is easy to pick up and nice to test with.
Here are a bunch of Vue-Test-Utils tips, tricks and features that you may or may not be aware of.
await Vue.nextTick()
instead of using a callback inside nextTick()
Use (Vue.nextTick()
or wrapper.vm.$nextTick
is used to wait until Vue has updated at the next tick, often used with async code or when changing the DOM)
I think this is quite well known at this point, but when Vue Test Utils first came out a lot of code that used nextTick()
would use a callback as its argument:
function someTest(done) {
// Some code setup here.
Vue.nextTick(function testSomethingAfterNextTick() {
expect(something).toBe(false);
done();
});
}
A cleaner way to this would be to use await
. If nextTick()
is called with no arguments then it returns a promise.
async function someTest() {
// Some code setup here.
await Vue.nextTick();
expect(something).toBe(false);
}
Things to notice: No calling of done()
in the callback, and the function must be marked as async
.
await nextTick()
after triggering events
Use Another common thing to see in tests which use nextTick()
after a trigger()
:
async function someTest() {
wrapper = mount(Component);
wrapper.trigger('click');
await Vue.nextTick();
expect(something).toBe(true);
}
This can be a little cleaner, as trigger()
returns Vue.nextTick()
anyway (which is a promise).
So you can get rid of the await nextTick()
and just await the trigger call:
async function someTest() {
wrapper = mount(Component);
await wrapper.trigger('click');
expect(something).toBe(true);
}
You can also await the results from the following other calls:
setChecked()
setData()
setSelected()
setProps()
setValue()
nextTick()
will mean errors are not caught
Be aware that using a callback in While still on the topic of nextTick()
there is one important fact to be aware of. If you have a callback function within nextTick()
and an error is thrown it will not show up in the test results.
To get around this problem there are two things which can be done - see the following code:
// this will not be caught
it('will time out', done => {
Vue.nextTick(() => {
expect(true).toBe(false);
done();
});
});
// the three following tests will work as expected
it('will catch the error using done', done => {
Vue.config.errorHandler = done;
Vue.nextTick(() => {
expect(true).toBe(false);
done();
});
});
it('will catch the error using a promise', () => {
return Vue.nextTick().then(function() {
expect(true).toBe(false);
});
});
it('will catch the error using async/await', async () => {
await Vue.nextTick();
expect(true).toBe(false);
});
Get emitted events from a component
You can get all emitted events from a component by calling wrapper.emitted()
.
// Test the 'someEventName' was fired 3 times:
expect(wrapper.emitted().someEventName.length).toBe(3);
// Test the payload for an event:
const expectedPayload = '...';
expect(wrapper.emitted().yourEvent[0]).toEqual(expectedPayload);
// Test something was not emitted:
expect(wrapper.emitted().foo).toBeFalsy();
Fake an emitted event from a child element
If you want to fake an emitted event from a child element, you can do the following:
import { shallowMount } from '@vue/test-utils'
import ParentComponent from '../components/ParentComponent'
import ChildComponent from '../components/ChildComponent'
describe('ParentComponent', () => {
it("displays 'Emitted!' when custom event is emitted", () => {
const wrapper = shallowMount(ParentComponent);
// next line acts as if the child component emitted 'custom'
wrapper.find(ChildComponent).vm.$emit('custom');
expect(wrapper.html()).toContain('Emitted!');
});
})
Get all listeners for a component in Vue Test Utils
Get all listeners with the vm.$listeners
attribute.
const wrapper = mount(ParentComponent);
const listeners = wrapper.vm.$listeners;
const childComponentListeners = wrapper.find(ChildComponent).vm.$listeners;
Stub out transitions with Vue Test Utils
Transitions can make testing a pain. Unless you are specifically testing some of the transition functionality, it is often a good idea to stub out the transition.
// stub function which will just render the children:
const transitionStub = () => ({
render: function(h) {
return this.$options._renderChildren
}
})
test('should render Foo, then hide it', async () => {
const wrapper = mount(Foo, {
stubs: {
// Stub out the transition:
transition: transitionStub()
}
})
expect(wrapper.text()).toMatch(/Foo/)
wrapper.setData({
show: false
})
await wrapper.vm.$nextTick()
expect(wrapper.text()).not.toMatch(/Foo/)
})
createLocalVue
and use the Router on it, the $route
and $router
properties are read-only
Remember when testing with Vue Router that if you use If you start to test things involving the Vue Router then you will often end up using createLocalVue
:
import { shallowMount, createLocalVue } from '@vue/test-utils'
import VueRouter from 'vue-router'
const localVue = createLocalVue()
localVue.use(VueRouter)
shallowMount(Component, {
localVue
})
Remember that when you do that, it makes the $route
(current route) and $router
(the router itself) read-only. If you have used the localVue.use(VueRouter)
and then use that when mounting, you will not be able to set mocked route data.
The following code is an example of code which will not work!
import { shallowMount, createLocalVue } from '@vue/test-utils'
import VueRouter from 'vue-router'
const localVue = createLocalVue()
localVue.use(VueRouter)
const $route = {
path: '/some/path'
}
const wrapper = shallowMount(Component, {
localVue,
mocks: {
// $route does not work! It was set to read only when using localVue.
$route
}
})
wrapper.props()
Get all Vue props with This is probably quite widely known, but you can access a component's props with the following:
const wrapper = mount(SomeComponent, {
propsData: {
name: 'webdevetc',
}
});
expect(wrapper.props().name).toBe('webdevetc');
render()
or renderToString()
If testing on a server and need to test rendered HTML, use render()
uses vue-server-renderer
under the hood, to render a component to static HTML - this is included in the @vue/server-test-utils
package.
const wrapper = await render(SomeComponent);
expect(wrapper.text()).toContain('<div></div>');
There is also a renderToString()
function.
is()
to check the type of a component
Use Sometimes you need to check that the output of mount()
or something from find()
is a certain component type. For that, you can use is
.
const wrapper = mount(SomeComponent);
expect(wrapper.is(SomeComponent)).toBe(true);
expect(wrapper.find('.modal').is(ModalComponent)).toBe(true);
find()
with the name
or ref
option
Use The find()
function has the ability to search for elements with a certain Vue component ref
identifier, or by name.
const wrapper = mount(SomeComponent);
const btn = wrapper.find({ ref: 'myButton'});
const input = wrapper.find({ name: 'myInput'});
createWrapper
to create a wrapper for a mounted Vue instance or HTML element
Use createWrapper()
creates a Wrapper for a mounted Vue instance, or an HTML element.
import { createWrapper } from '@vue/test-utils'
import Foo from './Foo.vue'
const Constructor = Vue.extend(Foo)
const vm = new Constructor().$mount()
const wrapper = createWrapper(vm)
expect(wrapper.vm.foo).toBe(true)
config.silent
option
Suppress Vue warnings by using the You could argue that you shouldn't do this. But to avoid notifications of your tests mutating props or other warnings you can use the config.silent = true
option.
import { config } from '@vue/test-utils';
config.silent = true;
find()
or findAll()
Retrieve the query selector used with After using find()
(or findAll()
) you may be in the situation where you want to check the query selector used to find the result. You can access this with the selector
property.
(I haven't seen any useful application of this, but it is useful to know for debugging.)
const wrapper = mount(Component);
const link = wrapper.find('li > a');
expect(link.selector).toBe('li > a');
Wrapper
method attributes()
to get an element attribute list
Use You can use the attributes()
function on a wrapper object to get the DOM node attributes.
If you provide an argument then it will return that attribute key value.
const wrapper = mount(InputComponent);
expect(wrapper.attributes().placeholder).toBe('Enter your email');
// use with argument:
expect(wrapper.attributes('placeholder')).toBe('Enter your email');
Wrapper
method classes()
to get an element class list
Use The classes()
method on a wrapper object will return the classes for the DOM node.
If an argument is provided then it will return true or false if the element has that class.
const wrapper = mount(InputComponent);
// with no arguments will return a list of classes:
const allClasses = wrapper.classes();
expect(allClasses).toContain('form-input');
// with an argument will return boolean:
const hasFormInputClass = wrapper.classes('form-input');
expect(hasFormInputClass).toBe(true);
contains()
Check if a wrapper contains an element or component with You can use contains()
to check if a Wrapper object contains an element or component matching the selector.
import TextInput from './TextInput.vue';
const wrapper = mount(ContactForm);
expect(wrapper.contains('label')).toBe(true);
expect(wrapper.contains(TextInput)).toBe(true);
exists()
on a Wrapper
or WrapperArray
Use If you need to check if a Wrapper is empty you can use exists()
.
const wrapper = mount(ContactForm);
expect(wrapper.exists()).toBe(true);
const buttons = wrapper.findAll('button');
const specificButton = wrapper.find('button.submit-button');
expect(buttons.exists()).toBe(true); // non empty WrapperArray
expect(specificButton.exists()).toBe(true);
find()
to search for a component! Use findComponent()
instead
Do not use Although it currently works, using find()
to find a component is deprecated so should not be used. Instead use findComponent()
instead.
import InputForm from './InputForm.vue';
const wrapper = mount(ContactForm);
// Do NOT do the following:
const deprecated = wrapper.find(InputForm);
// Instead you should:
const correct = wrapper.findComponent(InputForm);
There is also findAllComponents()
which returns a WrapperArray
object.
find()
calls
You can chain The following chained code is perfectly valid:
const button = wrapper.find('[data-name="MyButton"]');
expect(button.find('.icon').exists()).toBe(true);
// another example
// (could be done as a single selector in this case: 'form button')
const anotherExample = wrapper.find('form').find('button');
get()
instead of find()
when it must find something
Use find()
can return an empty result. If you need to ensure it finds something (or the test fails) you can use get()
const wrapper = mount(SomeComponent);
const button = wrapper.get('button');
Wrapper
objects
Do not use these deprecated functions on The following methods are deprecated on Wrapper
objects.
isEmpty()
isVisible()
isVueInstance()
name()
overview()
setMethods()
Wrapper
or WrapperArray
objects
Use these helper methods to set data on There are a few setting methods which work on Wrapper
or WrapperArray
objects. If applied to a WrapperArray
it will set it on all items.
How to use setChecked()
in Vue Test Utils
setChecked()
to set checked value for checkbox or radio input elements, and it automatically updates v-model
bound data.
const wrapper = mount(SomeComponent);
const radioInput = wrapper.find('input[type="radio"]');
radioInput.setChecked();
const checkboxInputs = wrapper.findAll('input[type="checkbox"]');
checkboxInputs.setChecked();
Using setSelected()
in Vue Test Utils
setSelected()
to set an <option> as selected in Vue Test Utils and update the bound v-model
data.
const wrapper = mount(SomeComponent);
const options = wrapper.find('select').findAll('option');
options.at(2).setSelected();
How to use setValue()
in Vue Test Utils
Use setValue()
on an text control input or select element to set that element's current value, and update the v-model
bound data.
const wrapper = mount(SomeComponent);
const textInput = wrapper.find('input[type="text"]');
textInput.setValue('new value');
const select = wrapper.find('select');
select.setValue('option val');
Using setData()
in Vue Test Utils
setData()
to set the wrapper's VM data (the reactive data in a Vue component).
Use it by sending an object as the argument.
const wrapper = mount(SomeComponent);
wrapper.setData({foo: 'bar'});
expect(wrapper.vm.foo).toBe('bar');
Using setProps()
in Vue Test Utils
setProps()
to set the wrapper's props. This works in a similar fashion as setData()
.
There is also setMethods()
but this is deprecated (but does currently work.)
filter()
on WrapperArray
objects
You can call If you use findAll()
(which returns a WrapperArray
object) you can use the filter()
method to filter those items.
This works in a very similar way to the normal Array.filter() method - pass it a predicate function which returns true or false.
const wrapper = mount(SomeComponent);
const allDivs = wrapper.findAll('div');
const divsWithActiveClass = allDivs.filter(
wrapper => wrapper.classes('active')
);
const divsWithCorrectText = allDivs.filter(
wrapper => wrapper.text() === 'foo'
);
expect(divsWithCorrectText).toHaveLength(3);
is()
on WrapperArray
objects to check that every wrapper inside it matches the selector
Use Sometimes you may want to check that every Wrapper
inside a WrapperArray
is a certain type.
const wrapper = mount(SomeComponent);
const allActiveElements = wrapper.findAll('.active');
expect(allActiveElements.is('button')).toBe(true);
data
gets merged with existing data
Vue mounting options: When mounting with the data
config, it will merge with the existing data
function.
const TheComponent = {
template: '<div>{{ foo }}///{{ bar }}</div>',
data() {
// The 'existing' data from the component:
return {
foo: 'COMPONENT_FOO',
bar: 'COMPONENT_BAR'
}
}
///////
const wrapper = mount(TheComponent, {
// The additional data which will merge/overwrite with the
// existing data in the component.
data(){
return {
bar: 'FROM_MOUNT_DATA'
}
}
});
// expect the 'foo' value to be from the component,
// but the 'bar' value should be what we provided in
// the call to mount()
expect(wrapper.text()).toBe('COMPONENT_FOO///FROM_MOUNT_DATA')
stubs
value is deprecated
Vue mounting options: supplying a string It is still very common to stub a component out by providing a string for the stub value:
...
stubs: { SomeComponent: '<div class="stubbed" />'}
...
This is commonly used but it is deprecated and should not be done.
The only non-deprecated values for the stubs object is a component (object) or boolean. (However, strings are still working in the current version of Vue Test Utils).
Here are some examples of how to stub out a component in Vue Test Utils:
import AValidComponent from '../AValidComponent.vue';
const wrapper = mount(Component, {
stubs: {
// The following line is deprecated but does work:
SomeChildComponent: '<div class="stubbed" />'
// the following 4 lines are all valid:
AnotherComponent: false,
DifferentComponent: false,
StubbedComponent: true,
StubbedByComponent: AValidComponent,
}
});
propsData
- Use propsData
mounting option to set initial props
Vue mounting options: This is probably well known, but to set props in Vue Test Utils you can set propsData
.
const wrapper = mount(Component, {
propsData: {
somePropName: 'the-value',
anotherProp: true,
}
}
});
This is actually just using the normal Vue functionality - you can use propsData
in your non test code too.
listeners
attribute to set a component instance's $listeners
object
Vue mounting options: use the Another trick that is probably well known, but you can set the listeners in the mount options.
const onClick = jest.fn();
const wrapper = mount(ComponentWhichUsesListeners, {
listeners: { click: onClick}
}
wrapper.trigger('click');
expect(onClick).toHaveBeenCalled();
});
parentComponent
option to set the component to use as a parent.
Vue mounting options: use the If you need to set a parent component when mounting a (child) component, you can set it with the parentComponent
option.
import Something from '../Something.vue';
const wrapper = mount(ComponentWhichUsesListeners, {
parentComponent: Something
}
// You can access it with wrapper.vm.$parent
});
Comments →Vue-Test-Utils Guide: Things You Might Not Know About Vue-Test-Utils