从 Vue Test Utils v1 迁移
回顾 VTU v1 -> VTU v2 的更改,以及一些代码片段来展示所需的修改。如果您遇到此处未记录的错误或行为差异,请 打开一个问题.
更改
propsData
现在是 props
在 VTU v1 中,您将使用 propsData
挂载选项传递道具。这令人困惑,因为您在 Vue 组件的 props
选项中声明道具。现在您可以使用 props
挂载选项传递 props
。propsData
将继续支持以实现向后兼容。
之前:
const App = {
props: ['foo']
}
const wrapper = mount(App, {
propsData: {
foo: 'bar'
}
}
之后:
const App = {
props: ['foo']
}
const wrapper = mount(App, {
props: {
foo: 'bar'
}
}
不再有 createLocalVue
在 Vue 2 中,插件通常会修改全局 Vue 实例并将各种方法附加到原型。从 Vue 3 开始,情况不再如此 - 您使用 createApp
而不是 new Vue
创建一个新的 Vue 应用程序,并使用 createApp(App).use(/* ... */)
安装插件。
为了避免在 Vue Test Utils v1 中污染全局 Vue 实例,我们提供了 createLocalVue
函数和 localVue
挂载选项。这将使您能够为每个测试拥有一个隔离的 Vue 实例,避免跨测试污染。在 Vue 3 中,这不再是一个问题,因为插件、mixin 等不会修改全局 Vue 实例。
对于大多数以前使用 createLocalVue
和 localVue
挂载选项来安装插件、mixin 或指令的情况,您现在可以使用 global
挂载选项。以下是一个使用 localVue
的组件和测试示例,以及它现在的样子(使用 global.plugins
,因为 Vuex 是一个插件)
之前:
import Vuex from 'vuex'
import { createLocalVue, mount } from '@vue/test-utils'
const App = {
computed: {
count() {
return this.$state.count
}
}
}
const localVue = createLocalVue()
localVue.use(Vuex)
const store = new Vuex.Store({
state: {
return { count: 1 }
}
})
const wrapper = mount(App, {
store
localVue
})
之后:
import { createStore } from 'vuex'
import { mount } from '@vue/test-utils'
const App = {
computed: {
count() {
return this.$state.count
}
}
}
const store = createStore({
state() {
return { count: 1 }
}
})
const wrapper = mount(App, {
global: {
plugins: [store]
}
})
mocks
和 stubs
现在位于 global
中
mocks
和 stubs
应用于所有组件,而不仅仅是您传递给 mount
的组件。为了反映这一点,mocks
和 stubs
位于新的 global
挂载选项中
之前:
const $route = {
params: {
id: '1'
}
}
const wrapper = mount(App, {
stubs: {
Foo: true
},
mocks: {
$route
}
}
之后:
const $route = {
params: {
id: '1'
}
}
const wrapper = mount(App, {
global: {
stubs: {
Foo: true
},
mocks: {
$route
}
}
}
shallowMount
和 renderStubDefaultSlot
shallowMount
旨在存根任何自定义组件。虽然这在 Vue Test Utils v1 中是这种情况,但存根组件仍然会渲染它们的默认 <slot />
。虽然这是无意的,但一些用户开始喜欢这个功能。此行为在 v2 中得到纠正 - 存根组件的插槽内容不会被渲染。
给定此代码
import { shallowMount } from '@vue/test-utils'
const Foo = {
template: `<div><slot /></div>`
}
const App = {
components: { Foo },
template: `
<div>
<Foo>
Foo Slot
</Foo>
</div>
`
}
之前:
describe('App', () => {
it('renders', () => {
const wrapper = shallowMount(App)
console.log(wrapper.html())
// renders:
// <div>
// <foo-stub>
// Foo Slot
// </foo-stub>
// </div>
})
})
之后:
describe('App', () => {
it('renders', () => {
const wrapper = shallowMount(App)
console.log(wrapper.html())
// renders:
// <div>
// <foo-stub>
// </foo-stub>
// </div>
})
})
您可以像这样启用旧的行为
import { config } from '@vue/test-utils'
config.global.renderStubDefaultSlot = true
destroy
现在是 unmount
以匹配 Vue 3
Vue 3 将 vm.$destroy
重命名为 vm.$unmount
。Vue Test Utils 也随之改变;wrapper.destroy()
现在是 wrapper.unmount()
。
scopedSlots
现在与 slots
合并
Vue 3 将 slot
和 scoped-slot
语法统一到一个语法下,即 v-slot
,您可以在 文档 中阅读。由于 slot
和 scoped-slot
现在已合并,因此 scopedSlots
挂载选项现在已弃用 - 只需对所有内容使用 slots
挂载选项即可。
slots
的范围现在公开为 params
当使用字符串模板作为插槽内容时,如果未使用包装的 <template #slot-name="scopeVar">
标签明确定义,则插槽范围在评估插槽时将作为 params
对象提供。
shallowMount(Component, {
- scopedSlots: {
+ slots: {
- default: '<p>{{props.index}},{{props.text}}</p>'
+ default: '<p>{{params.index}},{{params.text}}</p>'
}
})
findAll().at()
已删除
findAll()
现在返回一个 DOMWrapper 数组。
之前
wrapper.findAll('[data-test="token"]').at(0);
之后
wrapper.findAll('[data-test="token"]')[0];
createWrapper()
已删除
createWrapper()
现在仅是内部函数,不能再导入。如果您需要访问不是 Vue 组件的 DOM 元素的包装器,可以使用 new DOMWrapper()
构造函数。
之前
import { createWrapper } from "@vue/test-utils";
describe('App', () => {
it('renders', () => {
const body = createWrapper(document.body);
expect(body.exists()).toBe(true);
})
之后
import { DOMWrapper } from "@vue/test-utils";
describe('App', () => {
it('renders', () => {
const body = new DOMWrapper(document.body);
expect(body.exists()).toBe(true);
})
测试运行器升级说明
Vue Test Utils 与框架无关 - 您可以将其与您喜欢的任何测试运行器一起使用。
此语句是 @vue/test-utils
的核心。但我们确实认识到,在某些情况下,将代码库和相应的测试套件迁移到 vue@3
可能是一项相当大的工作。
本节尝试汇集我们的社区在进行迁移以及将底层测试运行堆栈更新到更现代版本时发现的一些常见问题。这些与 @vue/test-utils
无关,但我们希望它能帮助您完成这个重要的迁移步骤。
@vue/vue3-jest
+ jest@^28
如果您决定抓住机会将测试运行器工具升级到更现代的版本,请牢记以下几点。
ReferenceError: Vue is not defined
vue-jest#479
当使用 jest-environment-jsdom
包时,它默认从 package.json
browser
条目 加载库。您可以覆盖它以使用 node
导入,并修复此错误
// jest.config.js
module.exports = {
testEnvironmentOptions: {
customExportConditions: ["node", "node-addons"],
}
}
快照现在包含我的注释节点
如果您使用快照测试并且注释节点泄漏到您的快照中,请注意,comments
现在始终 保留,并且仅在生产环境中删除。您可以通过调整 app.config.compilerOptions
来覆盖此行为,以从快照中删除它们
- 通过
vue-jest
配置.js// jest.config.js module.exports = { globals: { 'vue-jest': { compilerOptions: { comments: false } } } }
- 通过
@vue/test-utils
mountingOptions.global.config
,全局或在每个测试的基础上。
与 v1 的比较
这是针对从 VTU 1 迁移过来的用户的表格,比较了这两个 API。
基本 API
导出 | 说明 |
---|---|
enableAutoDestroy | 被 enableAutoUnmount 替换 |
挂载选项
选项 | 说明 |
---|---|
mocks | 嵌套在 global 中 |
propsData | 现在称为 props |
provide | 嵌套在 global 中 |
mixins | 嵌套在 global 中 |
plugins | 嵌套在 global 中 |
component | 嵌套在 global 中 |
directives | 嵌套在 global 中 |
attachToDocument | 重命名为 attachTo 。参见 此处 |
scopedSlots | 已删除。ScopedSlots 在 Vue 3 中与 slots 合并 |
context | 已删除。与 Vue 2 不同,不再有意义。 |
localVue | 已删除。不再需要 - 在 Vue 3 中没有全局 Vue 实例需要修改。 |
listeners | 已删除。在 Vue 3 中不再存在 |
parentComponent | 已删除 |
包装器 API (挂载)
方法 | 说明 |
---|---|
find | 仅支持 querySelector 语法。使用 findComponent(Comp) 查找 Vue 组件 |
setValue | 适用于选择框、复选框、单选按钮、输入框、文本区域。返回 nextTick 。 |
trigger | 返回 nextTick 。你可以执行 await wrapper.find('button').trigger('click') |
destroy | 重命名为 unmount 以匹配 Vue 3 生命周期钩子名称。 |
contains | 已移除。使用 find |
emittedByOrder | 已移除。使用 emitted |
setSelected | 已移除。现在是 setValue 的一部分 |
setChecked | 已移除。现在是 setValue 的一部分 |
is | 已删除 |
isEmpty | 已移除。使用匹配器,例如 this |
isVueInstance | 已删除 |
name | 已删除 |
setMethods | 已删除 |