Home  >  Q&A  >  body text

Vue-Router simulation using Vue-Test-Utils and Vitest

<p>I'm trying to understand the logic of mocking Vue-Router with Vitest. </p> <p>To do this, I tried setting up and simulating my test environment on a very simple project. When I try to follow the official documentation of Vue-Test-Utils, I always get an error. I don't know if it's because they use Jest. </p> <p>Using a real vue-router solved my problem, but I think mocking a vue-router is better. </p> <p> Below I will first convey the source code of the project, and then the errors I received. </p> <h3>Home.vue</h3> <pre class="brush:php;toolbar:false;"><script setup lang="ts"> import {onMounted} from "vue"; import {useRoute} from "vue-router"; const route = useRoute() onMounted(() => { console.log(route.query) }) </script> <template> <div>Home</div> </template></pre> <h3>Home.spec.ts</h3> <pre class="brush:php;toolbar:false;">import {expect, it, vi} from "vitest"; import {mount} from "@vue/test-utils"; import Home from "../src/components/Home.vue" it('Home Test', async () => { const wrapper = mount(Home) expect(wrapper.exists()).toBeTruthy() })</pre> <h3>vite.config.ts</h3> <pre class="brush:php;toolbar:false;">/// <reference types="vitest" /> import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue()], test: { environment: 'jsdom', include: ['./test/**/*.spec.ts'], exclude: ['node_modules', 'dist'], globals: true } })</pre> <h3>My error message is as follows: ..</h3> <h3>What I tried</h3> <p>I tried to simulate vue-router like below</p> <pre class="brush:php;toolbar:false;">vi.mock('vue-router', () => ({ useRoute: vi.fn(), }))</pre> <p>Or just</p> <pre class="brush:php;toolbar:false;">vi.mock('vue-router')</pre> <h4>This is my final Home.spec.ts file</h4> <pre class="brush:php;toolbar:false;">import {expect, it, vi} from "vitest"; import {mount} from "@vue/test-utils"; import Home from "../src/components/Home.vue" vi.mock('vue-router') it('Home Test', async () => { const wrapper = mount(Home, { global: { stubs: ["router-link", "router-view"] } }) expect(wrapper.exists()).toBeTruthy() })</pre></p>
P粉190883225P粉190883225420 days ago571

reply all(1)I'll reply

  • P粉294954447

    P粉2949544472023-08-26 00:01:26

    First, I want to see router-link or router-view in Home.vue:

    <script setup lang="ts">
    import { onMounted } from 'vue';
    import { useRoute } from 'vue-router';
    
    const route = useRoute();
    
    onMounted(() => {
      console.log(route.query);
    });
    </script>
    
    <template>
      <router-link to="home">Go to home</router-link>
      <router-view />
    </template>
    

    So, Home.spec.ts should look like this:

    import { expect, it, vi } from 'vitest';
    import { mount } from '@vue/test-utils';
    import * as VueRouter from 'vue-router';
    import Home from '../src/components/Home.vue';
    
    describe('./path/to/Home.vue', () => {
      const useRouteSpy = vi.spyOn(VueRouter, 'useRoute');
      const getWrapper = () => mount(Home as any, {
        global: {
          stubs: {
            'router-link': { template: '<div/>' },
            'router-view': { template: '<div/>' },
          },
        },
      });
    
      it('the component should be mounted', () => {
        // ARRANGE
        const useRouteMock = useRouteSpy.mockImplementationOnce({ query: 'query' });
        // ACT
        const wrapper = getWrapper();
        // ASSERT
        expect(useRouteMock).toHaveBeenCalled();
        expect(wrapper.exists()).toBeTruthy();
      });
    });
    

    Some comments/suggestions:

    • Use description to define test context
    • Define a global function to mount components, reuse instead of duplication
    • Use .spyOn() and .mockImplementation...() for monitoring and simulation
    • Use some structured/direct way to write tests, such as AAA [arrange, act, assert] or GWT [given, when, then]. I've been testing it for a few years and still use it and it helps me understand what I'm testing
    • Use .toHaveBeenCalled...() Check if the mock is working as expected
    • mount() The stub in the function should be related to the component used in the template (so if you don't use it shouldn't be listed as a stub)

    Hope it helps, cheers!

    reply
    0
  • Cancelreply