vitest 单元测试配合@vue/test-utils 之 router 篇

文章展示了如何利用vitest进行Vue应用的单元测试,特别是与VueRouter结合的情况。通过示例代码解释了如何设置和测试路由切换,包括使用VueTestUtils的mount方法、expect断言以及flushPromises来处理异步路由变化。还提到了编程式导航的测试方法,利用vue-test-utils的spyOn来监听router.push方法的调用。

what is vitest & VueTestUtils & VueRouter

vitest 是由 vite 提供支持的极速单元测试框架,VueTestUtils 是 Vue.js 的官方测试实用程序库,Vue Router 是 Vue.js 的官方路由,以上均为各自官网对其的描述

demo

项目中使用路由是十分常见,所以对它来个单元测试也是十分必要的

// app.vue
<template>
  <nav>
    <RouterLink to="/">home</RouterLink>
    <RouterLink data-test="about" to="/about">about</RouterLink>
  </nav>
  <RouterView />
</template>

// home.vue
<template>
  <div>主页</div>
</template>

// about.vue
<template>
  <div>关于</div>
</template>
// spec | test
import { describe, it, expect } from 'vitest'
import { mount, flushPromises } from '@vue/test-utils'
import { createRouter, createWebHistory } from 'vue-router'
import App from '@/App.vue'
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'
describe('router-test', () => {
  const router = createRouter({
    history: createWebHistory(),
    routes: [
      { path: '/', component: Home },
      { path: '/about', component: About },
    ],
  })
  it('test1', async () => {
    router.push('/')
    await router.isReady()
    const wrapper = mount(App, {
      global: { plugins: [router] },
    })
    expect(wrapper.findComponent(Home).exists()).toBe(true)
  })
  it('test2', async () => {
    router.push('/')
    await router.isReady()
    const wrapper = mount(App, {
      global: { plugins: [router] },
    })
    expect(wrapper.html()).toContain('主页')
    await wrapper.find('[data-test="about"]').trigger('click')
    await flushPromises()
    expect(wrapper.html()).toContain('关于')
  })
})
  1. 此 demo 由组件部分和测试文件两个部分组成
  2. app 组件里是一个基础的单页应用,点击对应的 route-link,route-view 中展示对应组件
  3. 测试文件因为是在单元测试环境下,所以我们需要先安装 VueRouter,VueRouter 是一个插件,在挂载组件时使用安装选项安装global: {plugins: []}

    第一组测试首先执行了跳转,因为 VueRouter4 异步处理路由,需要告诉路由器何时准备就绪,所以使用了await router.isReady()

    组件通过 test-utils 库的查找组件的方法findComponet查找 Home,再通过exists()验证元素是否存在
    然后使用 vitest 库的 expect 创建断言,toBe 断言基础对象是否相等

    第二组测试初始部分与第一组相同

    组件通过 test-utils 库 html 方法返回元素的 HTML
    然后使用 vitest 库的 expect 创建断言,toContain 断言检查值是否在数组中
    再通过 find 方法返回查找元素,trigger 方法触发 DOM 事件,模拟用户点击的操作,同样是因为 VueRouter 的异步性质,我们需要再断言之前完成路由,由于没有可以等待的hasNavigated钩子,所以用 test-utils 提供的flushPromises替代,该方法会刷新所有已解决的 promise 程序,点击前后都断言了,会判断实际执行结果与预期结果是否一致,如果不一致则会抛出错误

tips

同样的这是一个简单的 demo,但它还是有很多值得注意的知识点

  • exists 使用该方法验证 findComponent 查找的组件是否存在,并返回一个 Boolean 值
  • flushPromise 刷新所有已解决的 promise 程序
  • 实际开发中还会有使用编程式导航的场景,通常是页面有一个按钮,按钮的点击事件执行router.push('xx')这样子,针对它的单元测试可以这样写
it('编程式导航', async () => {
  const wrapper = mount(App, {
    global: { plugins: [router] },
  })
  // vi.spyOn 在对象的方法或 getter/setter 上创建一个监听
  const spy = vi.spyOn(router, 'push') // 监听router的push方法
  // 模拟用户按下按钮
  await wrapper.find('button').trigger('click')
  // toHaveBeenCalledTimes 断言检查一个函数是否被调用了一定的次数
  expect(spy).toHaveBeenCalledTimes(1)
  // toHaveBeenCalledWith 断言检查一个函数是否被调用过,并且传入了指定的参数
  expect(spy).toHaveBeenCalledWith('/about')
  // 后面就是和上面的测试代码一样的逻辑了
})

其他文章

vitest 单元测试配合@vue/test-utils 之组件单元测试篇
vitest 单元测试配合@vue/test-utils 之 pinia 篇

PS D:\聚合四方\pcAdmin> npm outdated Package Current Wanted Latest Location Depended by @babel/core 7.0.0 7.0.0 7.27.1 node_modules/@babel/core pcAdmin @vue/cli-plugin-babel 3.5.3 3.5.3 5.0.8 node_modules/@vue/cli-plugin-babel pcAdmin @vue/cli-plugin-eslint 3.12.1 3.12.1 5.0.8 node_modules/@vue/cli-plugin-eslint pcAdmin @vue/cli-plugin-unit-jest 4.5.19 4.5.19 5.0.8 node_modules/@vue/cli-plugin-unit-jest pcAdmin @vue/cli-service 4.5.19 4.5.19 5.0.8 node_modules/@vue/cli-service pcAdmin @vue/test-utils 1.0.0-beta.29 1.0.0-beta.29 2.4.6 node_modules/@vue/test-utils pcAdmin autoprefixer 9.8.8 9.8.8 10.4.21 node_modules/autoprefixer pcAdmin axios 0.18.1 0.18.1 1.9.0 node_modules/axios pcAdmin babel-core 7.0.0-bridge.0 7.0.0-bridge.0 6.26.3 node_modules/babel-core pcAdmin babel-eslint 10.0.1 10.0.1 10.1.0 node_modules/babel-eslint pcAdmin babel-jest 26.6.3 26.6.3 29.7.0 node_modules/babel-jest pcAdmin chalk 2.4.2 2.4.2 5.4.1 node_modules/chalk pcAdmin chokidar 2.1.5 2.1.5 4.0.3 node_modules/chokidar pcAdmin clipboard 2.0.4 2.0.4 2.0.11 node_modules/clipboard pcAdmin codemirror 5.45.0 5.45.0 6.0.1 node_modules/codemirror pcAdmin compression-webpack-plugin 6.1.2 6.1.2 11.1.0 node_modules/compression-webpack-plugin pcAdmin connect 3.6.6 3.6.6 3.7.0 node_modules/connect pcAdmin driver.js 0.9.5 0.9.5 1.3.6 node_modules/driver.js pcAdmin dropzone 5.5.1 5.5.1 6.0.0-beta.2 node_modules/dropzone pcAdmin echarts 4.2.1 4.2.1 5.6.0 node_modules/echarts pcAdmin eslint 5.15.3 5.15.3 9.27.0 node_modules/eslint pcAdmin eslint-plugin-vue 5.2.2 5.2.2 10.1.0 node_modules/eslint-plugin-vue pcAdmin file-saver 2.0.1 2.0.1 2.0.5 node_modules/file-saver pcAdmin fuse.js 3.4.4 3.4.4 7.1.0 node_modules/fuse.js pcAdmin html-webpack-plugin 3.2.0 3.2.0 5.6.3 node_modules/html-webpack-plugin pcAdmin husky 1.3.1 1.3.1 9.1.7 node_modules/husky pcAdmin js-cookie 2.2.0 2.2.0 3.0.5 node_modules/js-cookie pcAdmin jszip 3.2.1 3.2.1 3.10.1 node_modules/jszip pcAdmin less-loader 7.3.0 7.3.0 12.3.0 node_modules/less-loader pcAdmin lint-staged 8.1.5 8.1.5 16.0.0 node_modules/lint-staged pcAdmin mockjs 1.0.1-beta3 1.0.1-beta3 1.1.0 node_modules/mockjs pcAdmin normalize.css 7.0.0 7.0.0 8.0.1 node_modules/normalize.css pcAdmin path-to-regexp 2.4.0 2.4.0 8.2.0 node_modules/path-to-regexp pcAdmin sass-loader 7.3.1 7.3.1 16.0.5 node_modules/sass-loader pcAdmin screenfull 4.2.0 4.2.0 6.0.2 node_modules/screenfull pcAdmin script-ext-html-webpack-plugin 2.1.3 2.1.3 2.1.5 node_modules/script-ext-html-webpack-plugin pcAdmin serve-static 1.16.2 1.16.2 2.2.0 node_modules/serve-static pcAdmin showdown 1.9.1 1.9.1 2.1.0 node_modules/showdown pcAdmin sortablejs 1.8.4 1.8.4 1.15.6 node_modules/sortablejs pcAdmin svg-sprite-loader 4.1.3 4.1.3 6.0.11 node_modules/svg-sprite-loader pcAdmin svgo 1.2.0 1.2.0 3.3.2 node_modules/svgo pcAdmin terser-webpack-plugin 2.3.8 2.3.8 5.3.14 node_modules/terser-webpack-plugin pcAdmin vue-i18n 7.3.2 7.3.2 11.1.3 node_modules/vue-i18n pcAdmin vue-loader 17.4.2 15.11.1 17.4.2 node_modules/vue-loader pcAdmin vue-router 3.0.2 3.0.2 4.5.1 node_modules/vue-router pcAdmin vue-splitpane 1.0.4 1.0.4 1.0.6 node_modules/vue-splitpane pcAdmin vue-template-compiler 2.6.10 2.6.10 2.7.16 node_modules/vue-template-compiler pcAdmin vuedraggable 2.20.0 2.20.0 2.24.3 node_modules/vuedraggable pcAdmin vuex 3.1.0 3.1.0 4.1.0 node_modules/vuex pcAdmin webpack 4.47.0 4.47.0 5.99.9 node_modules/webpack 怎么修复
05-22
vue-typescript-admin-template@0.1.0 D:\project-sky-admin-vue-ts3 ├─┬ @types/vue-router@2.0.0 │ └── vue-router@3.6.5 deduped ├─┬ @vue/cli-plugin-babel@3.12.1 │ └─┬ @vue/babel-preset-app@3.12.1 │ └─┬ @vue/babel-preset-jsx@1.4.0 │ └── vue@2.7.16 deduped ├─┬ @vue/cli-plugin-typescript@3.12.1 │ ├─┬ fork-ts-checker-webpack-plugin@0.5.2 │ │ └── typescript@3.6.2 deduped │ ├─┬ ts-loader@5.4.5 │ │ └── typescript@3.6.2 deduped │ ├─┬ tslint@5.20.1 │ │ ├─┬ tsutils@2.29.0 │ │ │ └── typescript@3.6.2 deduped │ │ └── typescript@3.6.2 deduped │ └── typescript@3.6.2 deduped ├─┬ @vue/cli-plugin-unit-jest@3.12.1 │ └─┬ vue-jest@3.0.7 │ └── vue@2.7.16 deduped ├─┬ @vue/eslint-config-typescript@4.0.0 │ └─┬ @typescript-eslint/eslint-plugin@1.13.0 │ └─┬ tsutils@3.21.0 │ └── typescript@3.6.2 deduped ├─┬ @vue/test-utils@1.3.6 │ └── vue@2.7.16 deduped ├─┬ element-ui@2.15.14 │ └── vue@2.7.16 deduped ├── typescript@3.6.2 ├─┬ vue-area-linkage@5.1.0 │ └── vue@2.7.16 deduped ├─┬ vue-class-component@7.2.6 │ └── vue@2.7.16 deduped ├─┬ vue-property-decorator@8.5.1 │ └── vue@2.7.16 deduped ├── vue-router@3.6.5 ├─┬ vue-svgicon@3.3.2 │ └── vue@2.7.16 deduped ├── vue@2.7.16 ├─┬ vuex-class@0.3.2 │ └── vue@2.7.16 deduped ├─┬ vuex-module-decorators@0.10.1 │ └── vue@2.7.16 deduped ├─┬ vuex-persistedstate@2.7.1 │ └── vue@2.7.16 deduped └─┬ vuex@3.6.2 └── vue@2.7.16 deduped PS D:\project-sky-admin-vue-ts3>
08-01
npm ls --dev npm warn config dev Please use --include=dev instead. healthkit-manage-front@6.24.12.100 C:\Users\x60102926\Desktop\HealthDeveloperService_manger\HealthKitManageFront ├── UNMET DEPENDENCY @element-plus/icons-vue@^2.0.10 ├── UNMET DEPENDENCY @kazupon/vue-i18n-loader@^0.3.0 ├── UNMET DEPENDENCY @types/diff@^5.0.9 ├── UNMET DEPENDENCY @types/webpack@^4.4.0 ├── UNMET DEPENDENCY @vue/cli-plugin-babel@^4.5.0 ├── UNMET DEPENDENCY @vue/cli-plugin-typescript@^4.5.15 ├── UNMET DEPENDENCY @vue/cli-service@4.5.0 ├── UNMET DEPENDENCY @vue/test-utils@^1.0.0-beta.20 ├── UNMET DEPENDENCY axios@1.8.4 ├── UNMET DEPENDENCY babel-core@7.0.0-bridge.0 ├── UNMET DEPENDENCY babel-plugin-component@^1.1.1 ├── UNMET DEPENDENCY colors-console@^1.0.3 ├── UNMET DEPENDENCY compressing@^1.5.1 ├── UNMET DEPENDENCY echarts@5.5.1 ├── UNMET DEPENDENCY element-plus@2.9.4 ├── UNMET DEPENDENCY lint-staged@^7.3.0 ├── UNMET DEPENDENCY moment@2.30.1 ├── UNMET DEPENDENCY node-sass@^4.13.0 ├── UNMET DEPENDENCY sass-loader@^7.0.1 ├── UNMET DEPENDENCY typescript@^4.9.4 ├── UNMET DEPENDENCY v-code-diff@1.12.0 ├── UNMET DEPENDENCY vue-cli-plugin-element@^1.0.0 ├── UNMET DEPENDENCY vue-echarts@6.7.3 ├── UNMET DEPENDENCY vue-facing-decorator@3.0.4 ├── UNMET DEPENDENCY vue-i18n@9.14.5 ├── UNMET DEPENDENCY vue-json-viewer@3.0.4 ├── UNMET DEPENDENCY vue-router@4.5.0 ├── UNMET DEPENDENCY vue@3.3.4 ├── UNMET DEPENDENCY webpack-bundle-analyzer@^3.0.3 └── UNMET DEPENDENCY xlsx@0.20.2 npm error code ELSPROBLEMS npm error missing: @element-plus/icons-vue@^2.0.10, required by healthkit-manage-front@6.24.12.100 npm error missing: @kazupon/vue-i18n-loader@^0.3.0, required by healthkit-manage-front@6.24.12.100 npm error missing: @types/diff@^5.0.9, required by healthkit-manage-front@6.24.12.100 npm error missing: @types/webpack@^4.4.0, required by healthkit-manage-front@6.24.12.100 npm error missing: @vue/cli-plugin-babel@^4.5.0, required by healthkit-manage-front@6.24.12.100 npm error missing: @vue/cli-plugin-typescript@^4.5.15, required by healthkit-manage-front@6.24.12.100 npm error missing: @vue/cli-service@4.5.0, required by healthkit-manage-front@6.24.12.100 npm error missing: @vue/test-utils@^1.0.0-beta.20, required by healthkit-manage-front@6.24.12.100 npm error missing: axios@1.8.4, required by healthkit-manage-front@6.24.12.100 npm error missing: babel-core@7.0.0-bridge.0, required by healthkit-manage-front@6.24.12.100 npm error missing: babel-plugin-component@^1.1.1, required by healthkit-manage-front@6.24.12.100 npm error missing: colors-console@^1.0.3, required by healthkit-manage-front@6.24.12.100 npm error missing: compressing@^1.5.1, required by healthkit-manage-front@6.24.12.100 npm error missing: echarts@5.5.1, required by healthkit-manage-front@6.24.12.100 npm error missing: element-plus@2.9.4, required by healthkit-manage-front@6.24.12.100 npm error missing: lint-staged@^7.3.0, required by healthkit-manage-front@6.24.12.100 npm error missing: moment@2.30.1, required by healthkit-manage-front@6.24.12.100 npm error missing: node-sass@^4.13.0, required by healthkit-manage-front@6.24.12.100 npm error missing: sass-loader@^7.0.1, required by healthkit-manage-front@6.24.12.100 npm error missing: typescript@^4.9.4, required by healthkit-manage-front@6.24.12.100 npm error missing: v-code-diff@1.12.0, required by healthkit-manage-front@6.24.12.100 npm error missing: vue-cli-plugin-element@^1.0.0, required by healthkit-manage-front@6.24.12.100 npm error missing: vue-echarts@6.7.3, required by healthkit-manage-front@6.24.12.100 npm error missing: vue-facing-decorator@3.0.4, required by healthkit-manage-front@6.24.12.100 npm error missing: vue-i18n@9.14.5, required by healthkit-manage-front@6.24.12.100 npm error missing: vue-json-viewer@3.0.4, required by healthkit-manage-front@6.24.12.100 npm error missing: vue-router@4.5.0, required by healthkit-manage-front@6.24.12.100 npm error missing: vue@3.3.4, required by healthkit-manage-front@6.24.12.100 npm error missing: webpack-bundle-analyzer@^3.0.3, required by healthkit-manage-front@6.24.12.100 npm error missing: xlsx@0.20.2, required by healthkit-manage-front@6.24.12.100 npm error A complete log of this run can be found in: C:\Users\x60102926\AppData\Local\npm-cache\_logs\2025-09-16T07_14_18_740Z-debug-0.log
09-17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值