SuperAPI AI 工具集

vue-test-utils-skilld

测试与质量

查看项目

更新于 10-16 03:21

技能介绍

用途

@vue/test-utils 是 Vue 3 的组件测试工具库,用于在测试中挂载组件、操作 DOM、查询子组件并断言渲染结果与事件。资料说明其与测试运行器无关,可用于 Vitest、Jest 或其它运行器,但需要一个类浏览器的 DOM 环境,例如 jsdom 或 happy-dom。该库需要 Vue 3.x 与 @vue/compiler-dom 3.x 作为 peer 依赖;@vue/server-renderer 3.x 是可选 peer 依赖,仅在需要 renderToString 时使用。

安装与快速开始

安装命令:npm install @vue/test-utils --save-dev

资料给出的快速示例:

import { mount } from '@vue/test-utils'
import Counter from './Counter.vue'

test('increments', async () => {
  const wrapper = mount(Counter, { props: { start: 1 } })
  await wrapper.find('button').trigger('click')
  expect(wrapper.text()).toContain('2')
})

主要能力

资料列出的公开 API 包括:

  • mount:挂载组件,返回 VueWrapper。
  • shallowMount:与 mount 相同,但会桩掉所有子组件。
  • renderToString:将组件 SSR 渲染为字符串,返回 Promise<string>。
  • flushPromises:等待挂起的非 Vue promise,例如被模拟的 API 调用、计时器。
  • enableAutoUnmount(hook):通过测试钩子自动卸载所有 wrapper。
  • disableAutoUnmount:停止自动卸载。
  • VueWrapper:已挂载组件实例的包装类。
  • DOMWrapper:DOM 元素的包装类,例如 new DOMWrapper(document.body)。
  • RouterLinkStub:用于 <router-link> 的桩组件。
  • config:共享的默认挂载选项与 wrapper 插件。
  • createWrapperError:内部函数,用于生成 find 未命中时返回的错误 wrapper。

使用方式与核心规则

资料列出的核心规则包括:

  • 对返回 promise 的方法都要 await:trigger、setValue、setProps、setData、renderToString、flushPromises。否则断言会在 DOM 更新前执行。
  • 元素必须存在时使用 get() / getComponent(),未命中会抛错;元素可能不存在时使用 find() / findComponent(),未命中返回 exists() 为 false 的错误 wrapper。
  • find() 只接受 CSS 选择器。查找子组件需使用 findComponent(Component)、findComponent({ name: 'Foo' })、findComponent({ ref: 'foo' }) 或 CSS 选择器。
  • 在测试初始化中注册一次 enableAutoUnmount(afterEach),防止测试间状态泄漏。
  • Vue 不跟踪的 promise(例如被模拟的 HTTP 客户端、setTimeout)使用 flushPromises()。
  • wrapper.vm 只可靠暴露组件实际暴露的内容:选项式 API 状态、defineExpose() 绑定(自 2.5.0 起,PR #2927)或 setup() 返回值。

示例:

import { enableAutoUnmount } from '@vue/test-utils'
import { afterEach } from 'vitest'

enableAutoUnmount(afterEach)

版本说明(2.4.10 到 2.5.1)

  • 破坏性变更(2.5.0):移除类组件支持。应挂载由 defineComponent、选项对象或 <script setup> 单文件组件定义的 Vue 组件。
  • 修复(2.5.0):子组件卸载时会清空其 emitted() 历史,应在卸载前断言事件。
  • 修复(2.5.0):defineExpose 绑定可在 findComponent(...).vm 上看到。
  • 修复(2.4.11):setData() 对同时使用 setup() 与 data() 的组件可正常工作。
  • 修复(2.4.11):trigger('keydown') 会设置符合规范的 event.code。
  • 类型(2.4.11):导出 GlobalMountOptions。

更早的 v2 里程碑:renderToString 在 2.3.0 加入用于 SSR 测试;html({ raw: true })、指令桩(vName: true)、多选 setValue 数组在 2.2.0 加入;enableAutoUnmount / disableAutoUnmount 取代 v1 的 enableAutoDestroy。

其它说明:propsData 仍可用但已废弃,应使用 props;stubs 接受记录对象(如 { Foo: true })或名称数组(如 ['Foo'])。

从 v1(Vue 2)迁移

资料给出的迁移要点:

  • propsData 改为 props;createLocalVue 移除,改用 global.plugins / global.mixins。
  • mocks、stubs、provide、directives 移到 global 下。
  • destroy() 改为 unmount();findAll().at(i) 改为 findAll()[i](返回数组)。
  • createWrapper() 移除,改用 new DOMWrapper(el)。
  • setChecked / setSelected 移除,合并到 setValue。
  • find() 不再按名称查找组件,应使用 findComponent。
  • shallowMount 不再渲染桩的默认插槽内容,可通过 config.global.renderStubDefaultSlot = true 恢复。
  • 移除项:is、isEmpty、isVueInstance、name、setMethods、contains、scopedSlots(已合并到 slots)。

最佳实践

资料给出的实践建议包括:

  • 优先使用 mount 加针对性的 global.stubs,而不是 shallowMount;浅层测试断言的是结构而非行为,且被桩掉的子组件会隐藏真实交互。
  • 如果确实要广泛使用桩,设置 config.global.renderStubDefaultSlot = true,让桩的默认插槽内容仍被渲染。
  • 用 vName 键来桩指令:global.stubs: { vTooltip: true },或传入替代指令对象。
  • <transition> 与 <transition-group> 默认被桩;也支持自定义过渡桩。
  • 通过 global.provide 传入 inject 值,与生产注入保持一致;对于带类型的注入键,可包装键:provide: { [injectionKey as symbol]: value }。
  • 测试组合式函数时,挂载一个最小宿主组件并从 wrapper.vm 读取状态。
  • 对带 async setup() 的组件,先包在 <Suspense> 宿主中再挂载。
  • 对 <Teleport>,可以桩掉它(global.stubs: { teleport: true }),或在 beforeEach 中创建目标元素并用 document.querySelector 查询。
  • 在不安装路由的情况下测试 <router-link> 周边逻辑时,使用 RouterLinkStub:global.stubs: { 'router-link': RouterLinkStub }。

适用场景与限制

适用场景:Vue 3 组件的单元测试与集成测试,包括表单与 v-model、事件断言、路由、Vuex/Pinia、Suspense、Teleport、SSR 等测试场景;资料提到测试配方涵盖这些方向。

限制:需要 Vue 3.x 与 @vue/compiler-dom 3.x;需要类浏览器 DOM 环境;2.5.0 起不再支持类组件;wrapper.vm 只可靠暴露组件实际暴露的内容;renderToString 需要可选的 @vue/server-renderer。