With apps getting more complex than ever, it’s important to test them automatically. We can do this with unit tests, and then we don’t have to test everything by hand.
In this article, we’ll look at how to test Vue 3 apps by writing a simple app and testing it.
Testing Form Triggered Events
We can test the events that are triggered when we submit the form.
For example, we can write:
import { mount } from '@vue/test-utils'
const EmailInput = {
template: `
<div>
<input type="email" v-model="email">
<button @click="submit">Submit</button>
</div>
`,
data() {
return {
email: ''
}
},
methods: {
submit() {
this.$emit('submit', this.email)
}
}
}
test('sets the value', async () => {
const wrapper = mount(EmailInput)
const input = wrapper.find('input')
await input.setValue('abc@mail.com')
expect(input.element.value).toBe('abc@mail.com')
})
test('submit event is triggered', async () => {
const wrapper = mount(EmailInput)
await wrapper.find('button').trigger('click')
expect(wrapper.emitted()).toHaveProperty('submit')
})
In the 2nd test, we get the button and trigger the click
event.
Then we check that the submit
event is emitted with the wrapper.emitted
method.
We can check what the event triggered with the argument that it’s emitted with.
For example, we can write:
import { mount } from '@vue/test-utils'
const EmailInput = {
template: `
<div>
<input type="email" v-model="email">
<button @click="submit">Submit</button>
</div>
`,
data() {
return {
email: ''
}
},
methods: {
submit() {
this.$emit('submit', this.email)
}
}
}
test('emits the input to its parent', async () => {
const wrapper = mount(EmailInput)
await wrapper.find('input').setValue('abc@mail.com')
await wrapper.find('button').trigger('click')
expect(wrapper.emitted('submit')[0][0]).toBe('abc@mail.com')
})
We mount the EmailInput
.
Then we call setValue
on the input to set its value.
Then we trigger the click
event on the button.
And we check that the submit
event is emitted with the input value.
Working with Various Form Elements
We can manipulate other form elements in our tests.
For instance, we can write:
import { mount } from '@vue/test-utils'
const FormComponent = {
template: `
<div>
<form @submit.prevent="submit">
<input type="email" v-model="form.email">
<textarea v-model="form.description"/>
<select v-model="form.city">
<option value="new-york">New York</option>
<option value="toronto">Toronto</option>
</select>
<input type="checkbox" v-model="form.subscribe"/>
<input type="radio" value="weekly" v-model="form.interval"/>
<input type="radio" value="monthly" v-model="form.interval"/>
<button type="submit">Submit</button>
</form>
</div>
`,
data() {
return {
form: {
email: '',
description: '',
city: '',
subscribe: false,
interval: ''
}
}
},
methods: {
async submit() {
this.$emit('submit', this.form)
}
}
}
test('submits a form', async () => {
const wrapper = mount(FormComponent)
await wrapper.find('input[type=email]').setValue('name@mail.com')
await wrapper.find('textarea').setValue('Lorem ipsum')
await wrapper.find('select').setValue('toronto')
await wrapper.find('input[type=checkbox]').setValue()
await wrapper.find('input[type=radio][value=monthly]').setValue()
})
We can use the setValue
method with textarea
, selecrt
, checkboxes and radio buttons.
Also, we can trigger complex events.
For instance, we can write:
import { mount } from '@vue/test-utils'
const FormComponent = {
template: `
<div>
<form @submit.prevent="submit">
<input type="email" v-model="form.email">
<textarea v-model="form.description"/>
<select v-model="form.city">
<option value="new-york">New York</option>
<option value="toronto">Toronto</option>
</select>
<input type="checkbox" v-model="form.subscribe"/>
<input type="radio" value="weekly" v-model="form.interval"/>
<input type="radio" value="monthly" v-model="form.interval"/>
<button type="submit">Submit</button>
</form>
</div>
`,
data() {
return {
form: {
email: '',
description: '',
city: '',
subscribe: false,
interval: ''
}
}
},
methods: {
async submit() {
this.$emit('submit', this.form)
}
}
}
test('submits a form', async () => {
const wrapper = mount(FormComponent)
const email = 'name@mail.com'
const description = 'Lorem ipsum'
const city = 'toronto'
await wrapper.find('input[type=email]').setValue(email)
await wrapper.find('textarea').setValue(description)
await wrapper.find('select').setValue(city)
await wrapper.find('input[type=checkbox]').setValue()
await wrapper.find('input[type=radio][value=monthly]').setValue()
await wrapper.find('form').trigger('submit.prevent')
expect(wrapper.emitted('submit')[0][0]).toMatchObject({
email,
description,
city,
subscribe: true,
interval: 'monthly',
})
})
We have the same component.
In the test, we mount the component and call setValue
to set the value of each field.
Then we check if the object we emitted with the submit
event matches the expected object with the toMatchObject
method.
We test the this.form
object in the submit
method matches what we have in the last line.
Conclusion
We can test form triggered events and set the values of various form elements in our Vue 3 component tests with Vue Test Utils.