Vue Test Utils 完整 API 速查表(v1 vs v2)
Vue Test Utils 分为 v1(适配 Vue 2) 和 v2(适配 Vue 3) 两大版本,核心差异源于 Vue 2/3 的响应式、组件模型变化。以下按 “功能模块” 分类,覆盖所有核心 API,标注新增、移除、变更项,适配日常测试与版本迁移需求。
一、组件挂载与环境配置 API
负责初始化组件测试环境,是所有测试的入口,v2 重点优化了 “全局配置隔离” 和 “Vue 3 特性适配”。
| 功能 | API | v1(Vue 2) | v2(Vue 3) | 示例代码 |
|---|---|---|---|---|
| 完全挂载组件 | mount | 支持,返回 Wrapper,适配 Vue 2 响应式 | 支持,返回 Wrapper,自动适配 Vue 3 异步渲染 | v1:const wrapper = mount(Foo, { propsData: { id: 1 } }) v2:const wrapper = mount(Foo, { props: { id: 1 } }) |
| 浅挂载组件(Stub 子组件) | shallowMount | 仅渲染当前组件,子组件用默认 Stub | 功能一致,Stub 逻辑适配 Vue 3 组件结构 | v1/v2:const wrapper = shallowMount(Foo, { stubs: ['ChildComponent'] }) |
| 挂载配置 - 传递 Props | propsData | 顶层配置,传递组件 Props | 移除,统一为 props 配置 | v1:{ propsData: { name: '测试' } } v2:{ props: { name: '测试' } } |
| 挂载配置 - 模拟全局对象 | mocks | 顶层配置,模拟 this.$xxx(如 $route) | 嵌套在 global 下,避免全局污染 | v1:{ mocks: { $message: { success: jest.fn() } } } v2:{ global: { mocks: { $message: { success: jest.fn() } } } } |
| 挂载配置 - 挂载到真实 DOM | attachToDocument | 顶层布尔值,挂载到 document.body | 重命名为 attachTo,支持自定义 DOM 节点 | v1:{ attachToDocument: true } v2:{ attachTo: document.createElement('div') } |
| 挂载配置 - 局部 Vue 实例 | localVue | 支持创建局部实例(避免全局插件污染) | 移除,Vue 3 无全局实例,无需隔离 | v1:const localVue = createLocalVue(); mount(Foo, { localVue }) v2:直接挂载,全局配置通过 global 隔离 |
| 挂载配置 - 配置全局插件 | - | 需通过 localVue.use(Plugin) 配置 | 新增 global.plugins,直接配置全局插件 | v2:{ global: { plugins: [VueRouter, ElementPlus] } } |
| 挂载配置 - 配置全局指令 | - | 需通过 localVue.directive() 注册 | 新增 global.directives,直接配置全局指令 | v2:{ global: { directives: { focus: focusDirective } } } |
二、元素与组件查询 API
用于定位组件内的 DOM 元素或子组件,v2 明确区分 “DOM 查询” 和 “组件查询”,避免歧义。
| 功能 | API | v1(Vue 2) | v2(Vue 3) | 示例代码 |
|---|---|---|---|---|
| 查找单个 DOM 元素 | find | 支持选择器(.class/#id)+ 组件对象 | 仅支持 DOM 选择器,查组件需用 findComponent | v1:wrapper.find(ChildComponent)(错误,应查 DOM) v2:wrapper.find('.btn-submit')(正确,仅查 DOM) |
| 查找多个 DOM 元素 | findAll | 支持选择器,返回 WrapperArray | 功能一致,返回 WrapperArray,适配 Vue 3 DOM 结构 | v1/v2:const itemWrappers = wrapper.findAll('.list-item') |
| 查找单个子组件 | - | 用 find(组件对象) 替代,易混淆 | 新增 findComponent,专门查询子组件 | v2:const childWrapper = wrapper.findComponent(ChildComponent) |
| 查找多个子组件 | - | 用 findAll(组件对象) 替代,易混淆 | 新增 findAllComponent,批量查询子组件 | v2:const childWrappers = wrapper.findAllComponent(ChildComponent) |
| 强制查找(不存在则报错) | - | 无此 API,查找失败返回空 Wrapper | 新增 get,适合确定元素存在的场景 | v2:const inputWrapper = wrapper.get('[name="username"]')(不存在则抛错) |
| 判断元素是否存在 | contains | 顶层方法,判断是否包含目标元素 | 移除,改用 find().exists() | v1:wrapper.contains('.btn') v2:wrapper.find('.btn').exists() |
| 获取根 DOM 元素 | element | Wrapper 属性,返回原生 DOM 节点 | 功能一致,返回原生 DOM 节点 | v1/v2:const rootDom = wrapper.element |
三、组件状态与属性操作 API
用于修改或读取组件的 Props、Data、DOM 属性等,v2 统一了异步操作的返回规范(需 await)。
| 功能 | API | v1(Vue 2) | v2(Vue 3) | 示例代码 |
|---|---|---|---|---|
| 修改组件 Props | setProps | 同步执行,修改后触发组件更新 | 异步执行,返回 Promise,需 await | v1:wrapper.setProps({ disabled: true }) v2:await wrapper.setProps({ disabled: true }) |
| 修改组件 Data | setData | 同步执行,直接修改 this.data | 功能一致,适配 Vue 3 响应式(Proxy) | v1/v2:wrapper.setData({ count: 10, form: { name: '' } }) |
| 给表单元素设值 | setValue | 仅支持输入框,同步执行 | 增强:支持输入框 / 单选 / 复选,返回 Promise | v1:wrapper.find('input').setValue('admin') v2:await wrapper.find('input[type="checkbox"]').setValue(true) |
| 给单选 / 复选设值 | setChecked | 单独 API,设置单选 / 复选状态 | 移除,功能合并到 setValue | v1:wrapper.find('input[type="radio"]').setChecked(true) v2:await wrapper.find('input[type="radio"]').setValue(true) |
| 获取组件 Props | props | 读取单个 / 所有 Props | 功能一致,适配 Vue 3 Props 校验 | v1/v2:const id = wrapper.props('id')(单个)const allProps = wrapper.props()(所有) |
| 获取 DOM 属性 | attributes | 读取单个 / 所有 DOM 属性(如 class/value) | 功能一致,返回字符串 / 对象 | v1/v2:const placeholder = wrapper.find('input').attributes('placeholder') const allAttrs = wrapper.find('input').attributes() |
| 获取元素文本 | text | 读取元素及其子元素的文本内容 | 功能一致,忽略隐藏元素文本 | v1/v2:const btnText = wrapper.find('.btn').text() |
| 获取元素 HTML 结构 | html | 读取元素的 HTML 字符串 | 功能一致,可通过配置隐藏注释节点 | v1/v2:const contentHtml = wrapper.find('.content').html() v2 隐藏注释:wrapper.find('.content').html({ comments: false }) |
| 获取元素类名 | classes | 读取单个 / 所有类名,返回数组 | 功能一致,支持筛选类名 | v1/v2:const hasActive = wrapper.find('.item').classes('active')(判断是否有该类)const allClasses = wrapper.find('.item').classes()(所有类) |
| 访问组件实例 | vm | Wrapper 属性,返回 Vue 2 组件实例 | 功能一致,返回 Vue 3 组件实例(Proxy) | v1:wrapper.vm.handleSubmit()(调用组件方法) v2:wrapper.vm.form.name(访问组件响应式数据) |
四、事件与交互 API
模拟用户操作(如点击、输入)或获取组件触发的事件,v2 统一了异步交互的返回逻辑。
| 功能 | API | v1(Vue 2) | v2(Vue 3) | 示例代码 |
|---|---|---|---|---|
| 触发 DOM / 组件事件 | trigger | 同步执行,触发事件(如 click/input) | 异步执行,返回 Promise,需 await | v1:wrapper.find('button').trigger('click') v2:await wrapper.find('button').trigger('click', { button: 0 })(第二个参数传事件参数) |
| 获取组件触发的自定义事件 | emitted | 返回事件对象,键为事件名,值为参数数组 | 功能一致,支持筛选事件参数 | v1/v2:const submitEvents = wrapper.emitted('submit')(所有 submit 事件)const firstArg = wrapper.emitted('submit')[0][0](第一个事件的第一个参数) |
| 清空组件触发的事件记录 | emittedByOrder | 返回按顺序排列的事件数组 | 移除,改用 emitted() 结合数组排序 | v1:const orderedEvents = wrapper.emittedByOrder() v2:const orderedEvents = Object.entries(wrapper.emitted()).flatMap(([name, args]) => args.map(arg => ({ name, arg }))) |
| 模拟输入框输入 | - | 需手动触发 input 事件 | setValue 自动模拟,无需手动触发 | v1:wrapper.find('input').trigger('input', { target: { value: 'admin' } }) v2:await wrapper.find('input').setValue('admin')(自动触发 input 事件) |
五、WrapperArray 专属 API
针对 findAll/findAllComponent 返回的 “多个 Wrapper 集合”,v2 增强了批量操作能力。
| 功能 | API | v1(Vue 2) | v2(Vue 3) | 示例代码 |
|---|---|---|---|---|
| 获取集合长度 | length | 属性,返回 Wrapper 数量 | 功能一致,无变化 | v1/v2:expect(wrapper.findAll('.item').length).toBe(3) |
| 获取指定索引的 Wrapper | at | 方法,按索引获取单个 Wrapper | 功能一致,支持负索引(v2.2+) | v1:const secondItem = wrapper.findAll('.item').at(1) v2:const lastItem = wrapper.findAll('.item').at(-1)(负索引表示倒数) |
| 遍历集合 | forEach | 方法,遍历每个 Wrapper 执行回调 | 功能一致,回调参数同 v1 | v1/v2:wrapper.findAll('.item').forEach((item, index) => { expect(item.text()).toBe(Item ${index}) }) |
| 映射集合为新数组 | map | 方法,将每个 Wrapper 映射为新值 | 功能一致,返回数组 | v1/v2:const itemTexts = wrapper.findAll('.item').map(item => item.text()) |
| 批量触发事件 | trigger | 不支持,需手动遍历 | 新增,批量触发所有 Wrapper 事件 | v2:await wrapper.findAll('input').trigger('blur') |
| 判断所有元素是否可见 | isVisible | 不支持,需手动遍历 | 新增,判断所有 Wrapper 是否可见 | v2:expect(wrapper.findAll('.active').isVisible()).toBe(true) |
| 筛选集合 | filter | 不支持,需手动遍历筛选 | 新增,按条件筛选 Wrapper | v2:const visibleItems = wrapper.findAll('.item').filter(item => item.isVisible()) |
六、组件卸载与清理 API
用于测试后销毁组件、清理环境,避免内存泄漏,v2 适配 Vue 3 的卸载逻辑。
| 功能 | API | v1(Vue 2) | v2(Vue 3) | 示例代码 |
|---|---|---|---|---|
| 销毁挂载的组件 | destroy | Wrapper 方法,销毁组件实例 | 重命名为 unmount,适配 Vue 3 卸载 API | v1:wrapper.destroy() v2:wrapper.unmount() |
| 自动销毁组件(测试后) | enableAutoDestroy | 全局方法,开启后每个测试用例后自动销毁 | 重命名为 enableAutoUnmount | v1:enableAutoDestroy(true) v2:enableAutoUnmount(true) |
| 取消自动销毁 | - | enableAutoDestroy(false) | enableAutoUnmount(false) | v1/v2 逻辑一致,仅方法名差异 |
七、插槽模拟 API
用于测试组件的插槽内容,v2 因 Vue 3 插槽语法变化,统一了 “普通插槽” 和 “作用域插槽” 的配置。
| 功能 | API | v1(Vue 2) | v2(Vue 3) | 示例代码 |
|---|---|---|---|---|
| 模拟普通插槽 | slots | 顶层配置,键为插槽名,值为 HTML / 组件 | 功能一致,支持渲染函数 | v1:{ slots: { default: '<div>默认插槽</div>', header: '<div>头部</div>' } } v2:{ slots: { default: () => h('div', '默认插槽') } } |
| 模拟作用域插槽 | scopedSlots | 顶层配置,键为插槽名,值为函数(接收插槽 props) | 移除,合并到 slots 配置(Vue 3 无作用域插槽概念) | v1:{ scopedSlots: { item: (props) => ${props.text} } } v2:{ slots: { item: (props) => h('div', props.text) } } |
八、异步操作辅助 API
用于处理组件中的异步逻辑(如异步请求、定时器),v2 结合 Vue 3 的 nextTick 优化了异步等待。
| 功能 | API | v1(Vue 2) | v2(Vue 3) | 示例代码 |
|---|---|---|---|---|
| 等待组件更新(nextTick) | vm.$nextTick | 通过组件实例调用,等待 DOM 更新 | 直接从 Vue 导入,或用 wrapper.vm.$nextTick | v1:await wrapper.vm.$nextTick() v2:import { nextTick } from 'vue'; await nextTick() |
| 模拟定时器 | - | 需手动用 Jest 模拟 setTimeout | 逻辑一致,结合 Jest useFakeTimers | v1/v2:jest.useFakeTimers(); wrapper.vm.delayFn(); jest.runAllTimers(); |
| 模拟异步请求 | - | 用 Jest mock 模拟 API 函数 | 逻辑一致,无版本差异 | v1/v2:import { fetchData } from './api'; jest.mock('./api'); fetchData.mockResolvedValue({ code: 200 }) |