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.
Test Apps with Vue Router
We can test apps that use the Vue Router with a mock router.
This way, we can test our component in isolation without worrying about the router.
src/views/Edit.vue
<template>
<button @click="redirect">Click to Edit</button>
</template>
<script>
export default {
props: ["authenticated"],
methods: {
redirect() {
if (this.authenticated) {
this.$router.push(`/posts/${this.$route.params.id}/edit`);
} else {
this.$router.push("/404");
}
},
},
};
</script>
src/views/Edit.vue
<template>
<div>Post {{$route.params.id}}</div>
</template>
src/views/NotFound.vue
<template>
<div>404</div>
</template>
index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import Edit from '../views/Edit.vue'
import Post from '../views/Post.vue'
import NotFound from '../views/NotFound.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/edit/:id',
name: 'Edit',
component: Edit
},
{
path: '/posts/:id',
name: 'post',
component: Post
},
{
path: '/404',
name: 'not-found',
component: NotFound
},
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
tests/unit/example.spec.js
import { mount } from '@vue/test-utils'
import Edit from '@/views/Edit'
describe('component handles routing correctly', () => {
it('allows authenticated user to edit a post', async () => {
const mockRoute = {
params: {
id: 1
}
}
const mockRouter = {
push: jest.fn()
}
const wrapper = mount(Edit, {
props: {
authenticated: true
},
global: {
mocks: {
$route: mockRoute,
$router: mockRouter
}
}
})
await wrapper.find('button').trigger('click')
expect(mockRouter.push).toHaveBeenCalledWith('/posts/1/edit')
})
it('redirect an unauthenticated user to 404', async () => {
const mockRoute = {
params: {
id: 1
}
}
const mockRouter = {
push: jest.fn()
}
const wrapper = mount(Edit, {
props: {
authenticated: false
},
global: {
mocks: {
$route: mockRoute,
$router: mockRouter
}
}
})
await wrapper.find('button').trigger('click')
expect(mockRouter.push).toHaveBeenCalledWith('/404')
})
})
The Vue app has several routes and we map them to routes.
Also, we added a group of tests that uses the mock router to test the components.
We add the mockRoute
to add a mock route object.
And we create the mockRouter
by adding the push
method to it.
Its value is a mocked function.
Also, when we mount the component, we pass in the props
and global
properties.
The mocks
have the $route
and $router
properties that we want to mock.
In the first test, we get the button in the Edit
component and click it.
And we check that the mockRouter.push
method goes to /posts/1/edit
.
In the 2nd test, we do the same thing but with the the authenticated
prop set to false
.
And we check that we’re redirected to the /404
route when we click on the button.
Conclusion
We can test our components with a mocked version of Vue Router in our Vue 3 app tests.