In this article we will test Vue Router with Vitest. As it's a small, testing application we'll use real Vue Router.
Instead of using real Vue Router there is a way to create mock version of router.
That approach allow as to test only these features that we want to and its recommended for more complex applications
Create a sample application using Vue Router and the Composition API
WelcomePage.vue
Inside our <script setup>
, we use the useRouter
functions. To get the user data we access to store by call useStore
function.
WelcomePage component contains the button. After clicked on these button onClick
function should be called and new router parameters should be pushed.
Depending on whether the user has an ID or not, parameters will be different - name, params and query for user with ID and only name for user without ID.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| <script setup>
import { useRouter } from 'vue-router'
import { useStore } from ' ../stores/index.js'
import { computed } from 'vue'
const store = useStore()
const router = useRouter()
const userId = store.userId
const userName = store. userName
const buttonText = computed () => {
return userId ? "Go to profile" : "Create account"
})
function onClick() {
if (userId) {
router. push ({
name: "User",
params: { userId: userId },
query: {
name: userName,
},
}) else {
router.push({
name: "CreateAccount",
})
}
}
</script>
<template>
<div>
<h1>Welcome to our website!</h1>
<button @click="onClick">{{ buttonText }}</button>
</div>
</template>
|
Let's test the navigation
Setup
- Import router and store
- Create a local router
- Creating a pinia instance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| import { describe, it, expect, beforeEach } from 'vitest';
import { mount } from '@vue/test-utils';
import { setActivePinia, createPinia } from 'pinia';
import { useStore } from '../stores/index.js';
import router from '../router';
import { createRouter, createWebHistory } from 'vue-router';
import WelcomePage from '../components/WelcomePage.vue';
// create local router
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: 'Welcome',
component: WelcomePage,
},
],
});
describe('WelcomePage', () => {
let pinia;
let wrapper;
beforeEach(() => {
// creating a pinia instance
pinia = createPinia();
setActivePinia(pinia);
});
});
|
Implementation
Implementation steps for both tests are the same.
- Mock function for router push method
- Use the testing pinia
- Set the value for name and id state
- Mock the routing using the global.mocks property
- Call onClick
function
- Expect router to be called with proper parameters
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| it('redirect user to User page', async () => {
const push = vi.spyOn(router, 'push');
const store = useStore();
store.userName = 'Jenifer';
store.userId = 12345;
wrapper = mount(WelcomePage, {
global: {
plugins: [router],
},
});
wrapper.vm.onClick();
expect(push).toHaveBeenCalledTimes(1);
expect(push).toHaveBeenCalledWith({
name: 'User',
params: { userId: 12345 },
query: {
name: 'Jenifer',
},
});
});
it('redirect user to CreateAccount page', async () => {
const push = vi.spyOn(router, 'push');
const store = useStore();
store.userName = null;
store.userId = null;
wrapper = mount(WelcomePage, {
global: {
plugins: [router],
},
});
wrapper.vm.onClick();
expect(push).toHaveBeenCalledTimes(1);
expect(push).toHaveBeenCalledWith({
name: 'CreateAccount',
});
});
|
UserProfile.vue
In the second component we display the user name. This name comes from the route query, so just like in the previous component, we use the useRouter
function.
In this test case, we want to check that the computed property returns the correct value and that the HTML element displays it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| <script setup>
import { computed } from "vue";
import { useRoute } from "vue-router";
const route = useRoute();
const userName = computed(() => {
return route.query.name;
});
</script>
<template>
<h1 class="welcome-message">Welcome {{ userName }}!</h1>
</template>
|
Now let's write the test.
Setup
- Import router
- Create a local router
- Mock route query value
- Mock the routing using the global.mocks property
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| import { describe, it, expect, beforeEach } from 'vitest';
import { shallowMount } from '@vue/test-utils';
import router from '../router';
import { createRouter, createWebHistory } from 'vue-router';
import UserProfile from '../components/UserProfile.vue';
// create local router
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/user',
name: 'User',
component: UserProfile,
},
],
});
router.currentRoute.value.query = {
name: 'Jenifer',
};
describe('UserProfile', () => {
let wrapper;
beforeEach(() => {
wrapper = shallowMount(UserProfile, {
global: {
plugins: [router],
},
});
});
});
|
Implementation
Everything we need is already configured. Now we just need to check whether the expected behavior is correct.
1
2
3
4
| it('userName should return route query name value', async () => {
expect(wrapper.vm.userName).toEqual('Jenifer');
expect(wrapper.html()).toContain('Welcome Jenifer!');
});
|
I hope this article was helpful and you will now be able to test Vue Router in your application. To see the tested example go to app repsitory on github.
Improve your UI/UX
If you need help with Vue Router and Vitest, our team is here to assist you. Whether you're setting up dynamic routes, testing your Vue components, or integrating unit tests with Vitest, we have the expertise to ensure your project runs smoothly. Reach out for tailored solutions and expert guidance on your Vue.js and testing workflows here.
Written by:
Ewelina Zwolenik
Frontend Developer
Ewelina is an amazing frontend developer who's great at working with Vue.js, HTML, CSS, and Tailwind CSS. She has a sharp eye for design and knows how to turn ideas into beautiful, responsive websites and apps that look great on any device.
Ewelina is an amazing frontend developer who's great at working with Vue.js, HTML, CSS, and Tailwind CSS. She has a sharp eye for design and knows how to turn ideas into beautiful, responsive websites and apps that look great on any device.