带有 Vue-Test-Utils 和 Vitest 的 Vue-Router 模拟

问题描述 投票:0回答:3

我试图理解用 Vitest 模拟 Vue-Router 的逻辑。

为此,我尝试在一个非常简单的项目上设置并模拟我的测试环境。当我尝试按照Vue-Test-Utils的官方文档进行操作时,总是出现错误。我不知道是不是因为他们用Jest。

使用 real vue-router 解决了我的问题,但我认为模拟 vue-router 更好。

下面我先传达一下项目的源码,然后是我收到的错误。

首页.vue

<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>

首页.spec.ts

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()
})

vite.config.ts

/// <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
  }
})

我的错误信息如下:..

我尝试过的方法

我尝试像下面这样模拟 vue-router

vi.mock('vue-router', () => ({
    useRoute: vi.fn(),
}))

或者只是

vi.mock('vue-router')

这是我的最终 Home.spec.ts 文件

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()
})
vue.js unit-testing mocking vue-router vitest
3个回答
3
投票

首先,我期望在

router-link
中看到
router-view
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>

所以,

Home.spec.ts
应该是这样的:

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();
  });
});

一些评论/建议:

  • 使用描述来界定测试上下文
  • 定义一个全局函数来挂载组件,复用而不是重复
  • 使用
    .spyOn()
    .mockImplementation...()
    进行监视和嘲笑
  • 使用一些结构化/直接的方式来编写测试,例如 AAA [安排、行动、断言] 或 GWT [给定、何时、然后]。我已经测试了几年并且仍在使用它,它可以帮助我理解我正在测试的内容
  • 使用
    .toHaveBeenCalled...()
    检查模拟是否按预期工作
  • mount()
    函数中的存根应与模板中使用的组件相关(因此,如果您不使用
    <router-view>
    ,则不应将其列为存根)

希望有帮助, 干杯!


1
投票

如果有人需要做同样的事情,现在你可以使用 vue-router-mock

轻松模拟 vue-router
// for example
import { getRouter } from 'vue-router-mock'

test('should move to /dashboard', () => {
 const route = getRouter()
 wrapper.router.push('/dashboard')
 console.log(route.currentRoute.value.fullPath) // /dashboard
})

0
投票

我能想到的最简单的方法如下所示:

在我的生产代码中,我尝试访问这样的变量

route.params.entityId

这会在我的测试代码中产生像您一样的错误。

设置如下:

import {useRoute} from "vue-router";
   
vi.mock('vue-router')
    
describe('MainPanelEntityPage', () => {

  useRoute.mockReturnValue({
    params: {
      entityId: "17"
    },
  })

  it('should be mounted', async () => {
    const wrapper = mount(MainPanelEntityPage)
     ...
  }
}

我能够从模拟的路由参数中检索“17”作为实体ID。

希望有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.