API 参考
mount
创建一个包含已挂载和渲染的 Vue 组件以进行测试的包装器。请注意,当使用 Vitest 模拟日期/计时器时,这必须在 vi.setSystemTime
之后调用。
签名
interface MountingOptions<Props, Data = {}> {
attachTo?: Element | string
attrs?: Record<string, unknown>
data?: () => {} extends Data ? any : Data extends object ? Partial<Data> : any
props?: (RawProps & Props) | ({} extends Props ? null : never)
slots?: { [key: string]: Slot } & { default?: Slot }
global?: GlobalMountOptions
shallow?: boolean
}
function mount(Component, options?: MountingOptions): VueWrapper
详情
mount
是 Vue 测试工具公开的主要方法。它创建一个包含并渲染正在测试的组件的 Vue 3 应用程序。作为回报,它创建一个包装器来对组件进行操作和断言。
import { mount } from '@vue/test-utils'
const Component = {
template: '<div>Hello world</div>'
}
test('mounts a component', () => {
const wrapper = mount(Component, {})
expect(wrapper.html()).toContain('Hello world')
})
请注意,mount
接受第二个参数来定义组件的状态配置。
示例:使用组件道具和 Vue 应用程序插件进行挂载
const wrapper = mount(Component, {
props: {
msg: 'world'
},
global: {
plugins: [vuex]
}
})
options.global
在组件状态中,您可以通过 MountingOptions.global
配置属性 配置上述 Vue 3 应用程序。这对于提供您的组件期望可用的模拟值非常有用。
提示
如果您发现自己必须为许多测试设置常见的应用程序配置,那么您可以使用导出的 config
对象 为整个测试套件设置配置。
attachTo
指定要挂载组件的节点。在使用 renderToString
时不可用。
签名
attachTo?: Element | string
详情
可以是有效的 CSS 选择器,或连接到文档的 Element
。
请注意,组件被附加到节点,它不会替换节点的全部内容。如果您在多个测试中将组件挂载到同一个节点上 - 确保在每次测试后通过调用 wrapper.unmount()
将其卸载,这将从节点中删除渲染的元素。
Component.vue
:
<template>
<p>Vue Component</p>
</template>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
document.body.innerHTML = `
<div>
<h1>Non Vue app</h1>
<div id="app"></div>
</div>
`
test('mounts on a specific element', () => {
const wrapper = mount(Component, {
attachTo: document.getElementById('app')
})
expect(document.body.innerHTML).toBe(`
<div>
<h1>Non Vue app</h1>
<div id="app"><div data-v-app=""><p>Vue Component</p></div></div>
</div>
`)
})
attrs
将 HTML 属性设置为组件。
签名
attrs?: Record<string, unknown>
详情
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('attrs', () => {
const wrapper = mount(Component, {
attrs: {
id: 'hello',
disabled: true
}
})
expect(wrapper.attributes()).toEqual({
disabled: 'true',
id: 'hello'
})
})
请注意,设置已定义的道具将始终胜过属性
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('attribute is overridden by a prop with the same name', () => {
const wrapper = mount(Component, {
props: {
message: 'Hello World'
},
attrs: {
message: 'this will get overridden'
}
})
expect(wrapper.props()).toEqual({ message: 'Hello World' })
expect(wrapper.attributes()).toEqual({})
})
data
覆盖组件的默认 data
。必须是一个函数。
签名
data?: () => {} extends Data ? any : Data extends object ? Partial<Data> : any
详情
Component.vue
<template>
<div>Hello {{ message }}</div>
</template>
<script>
export default {
data() {
return {
message: 'everyone'
}
}
}
</script>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('data', () => {
const wrapper = mount(Component, {
data() {
return {
message: 'world'
}
}
})
expect(wrapper.html()).toContain('Hello world')
})
props
在挂载时在组件上设置道具。
签名
props?: (RawProps & Props) | ({} extends Props ? null : never)
详情
Component.vue
:
<template>
<span>Count: {{ count }}</span>
</template>
<script>
export default {
props: {
count: {
type: Number,
required: true
}
}
}
</script>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('props', () => {
const wrapper = mount(Component, {
props: {
count: 5
}
})
expect(wrapper.html()).toContain('Count: 5')
})
slots
在组件上设置插槽的值。
签名
type Slot = VNode | string | { render: Function } | Function | Component
slots?: { [key: string]: Slot } & { default?: Slot }
详情
插槽可以是字符串或任何有效的组件定义,无论是从 .vue
文件导入还是内联提供
Component.vue
:
<template>
<slot name="first" />
<slot />
<slot name="second" />
</template>
Bar.vue
:
<template>
<div>Bar</div>
</template>
Component.spec.js
:
import { h } from 'vue';
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
import Bar from './Bar.vue'
test('renders slots content', () => {
const wrapper = mount(Component, {
slots: {
default: 'Default',
first: h('h1', {}, 'Named Slot'),
second: Bar
}
})
expect(wrapper.html()).toBe('<h1>Named Slot</h1>Default<div>Bar</div>')
})
global
签名
type GlobalMountOptions = {
plugins?: (Plugin | [Plugin, ...any[]])[]
config?: Partial<Omit<AppConfig, 'isNativeTag'>>
mixins?: ComponentOptions[]
mocks?: Record<string, any>
provide?: Record<any, any>
components?: Record<string, Component | object>
directives?: Record<string, Directive>
stubs?: Stubs = Record<string, boolean | Component> | Array<string>
renderStubDefaultSlot?: boolean
}
您可以在每个测试的基础上以及针对整个测试套件配置所有 global
选项。 查看如何配置项目范围的默认值.
global.components
在全局范围内将组件注册到挂载的组件。
签名
components?: Record<string, Component | object>
详情
Component.vue
:
<template>
<div>
<global-component />
</div>
</template>
<script>
import GlobalComponent from '@/components/GlobalComponent'
export default {
components: {
GlobalComponent
}
}
</script>
GlobalComponent.vue
:
<template>
<div class="global-component">My Global Component</div>
</template>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import GlobalComponent from '@/components/GlobalComponent'
import Component from './Component.vue'
test('global.components', () => {
const wrapper = mount(Component, {
global: {
components: {
GlobalComponent
}
}
})
expect(wrapper.find('.global-component').exists()).toBe(true)
})
global.config
配置 Vue 的应用程序全局配置.
签名
config?: Partial<Omit<AppConfig, 'isNativeTag'>>
global.directives
在全局范围内将 指令 注册到挂载的组件。
签名
directives?: Record<string, Directive>
详情
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Directive from '@/directives/Directive'
const Component = {
template: '<div v-bar>Foo</div>'
}
test('global.directives', () => {
const wrapper = mount(Component, {
global: {
directives: {
Bar: Directive // Bar matches v-bar
}
}
})
})
global.mixins
在全局范围内将 混合 注册到挂载的组件。
签名
mixins?: ComponentOptions[]
详情
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('global.mixins', () => {
const wrapper = mount(Component, {
global: {
mixins: [mixin]
}
})
})
global.mocks
模拟全局实例属性。可用于模拟 this.$store
、this.$router
等。
签名
mocks?: Record<string, any>
详情
警告
这旨在模拟由第三方插件注入的变量,而不是 Vue 的本机属性,例如 $root、$children 等。
Component.vue
:
<template>
<button @click="onClick" />
</template>
<script>
export default {
methods: {
onClick() {
this.$store.dispatch('click')
}
}
}
</script>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('global.mocks', async () => {
const $store = {
dispatch: jest.fn()
}
const wrapper = mount(Component, {
global: {
mocks: {
$store
}
}
})
await wrapper.find('button').trigger('click')
expect($store.dispatch).toHaveBeenCalledWith('click')
})
global.plugins
在挂载的组件上安装插件。
签名
plugins?: (Plugin | [Plugin, ...any[]])[]
详情
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
import myPlugin from '@/plugins/myPlugin'
test('global.plugins', () => {
mount(Component, {
global: {
plugins: [myPlugin]
}
})
})
要使用带有选项的插件,可以传递一个选项数组。
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('global.plugins with options', () => {
mount(Component, {
global: {
plugins: [Plugin, [PluginWithOptions, 'argument 1', 'another argument']]
}
})
})
global.provide
提供要通过 inject
在 setup
函数中接收的数据。
签名
provide?: Record<any, any>
详情
Component.vue
:
<template>
<div>Theme is {{ theme }}</div>
</template>
<script>
import { inject } from 'vue'
export default {
setup() {
const theme = inject('Theme')
return {
theme
}
}
}
</script>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('global.provide', () => {
const wrapper = mount(Component, {
global: {
provide: {
Theme: 'dark'
}
}
})
console.log(wrapper.html()) //=> <div>Theme is dark</div>
})
如果您使用 ES6 Symbol
作为您的提供键,您可以将其用作动态键
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
const ThemeSymbol = Symbol()
mount(Component, {
global: {
provide: {
[ThemeSymbol]: 'value'
}
}
})
global.renderStubDefaultSlot
渲染 default
插槽内容,即使使用 shallow
或 shallowMount
。
签名
renderStubDefaultSlot?: boolean
详情
默认为 false。
Component.vue
<template>
<slot />
<another-component />
</template>
<script>
export default {
components: {
AnotherComponent
}
}
</script>
AnotherComponent.vue
<template>
<p>Another component content</p>
</template>
Component.spec.js
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('global.renderStubDefaultSlot', () => {
const wrapper = mount(ComponentWithSlots, {
slots: {
default: '<div>My slot content</div>'
},
shallow: true,
global: {
renderStubDefaultSlot: true
}
})
expect(wrapper.html()).toBe(
'<div>My slot content</div><another-component-stub></another-component-stub>'
)
})
由于技术限制,此行为无法扩展到除默认插槽之外的其他插槽。
global.stubs
在挂载的组件上设置全局存根。
签名
stubs?: Record<any, any>
详情
它默认情况下会存根 Transition
和 TransitionGroup
。
Component.vue
:
<template>
<div><foo /></div>
</template>
<script>
import Foo from '@/Foo.vue'
export default {
components: { Foo }
}
</script>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('global.stubs using array syntax', () => {
const wrapper = mount(Component, {
global: {
stubs: ['Foo']
}
})
expect(wrapper.html()).toEqual('<div><foo-stub></div>')
})
test('global.stubs using object syntax', () => {
const wrapper = mount(Component, {
global: {
stubs: { Foo: true }
}
})
expect(wrapper.html()).toEqual('<div><foo-stub></div>')
})
test('global.stubs using a custom component', () => {
const CustomStub = {
name: 'CustomStub',
template: '<p>custom stub content</p>'
}
const wrapper = mount(Component, {
global: {
stubs: { Foo: CustomStub }
}
})
expect(wrapper.html()).toEqual('<div><p>custom stub content</p></div>')
})
shallow
从组件中存根所有子组件。
签名
shallow?: boolean
详情
默认为 false。
Component.vue
<template>
<a-component />
<another-component />
</template>
<script>
export default {
components: {
AComponent,
AnotherComponent
}
}
</script>
Component.spec.js
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('shallow', () => {
const wrapper = mount(Component, { shallow: true })
expect(wrapper.html()).toEqual(
`<a-component-stub></a-component-stub><another-component-stub></another-component-stub>`
)
})
提示
shallowMount()
是使用 shallow: true
挂载组件的别名。
包装器方法
当您使用 mount
时,会返回一个 VueWrapper
,它包含许多用于测试的有用方法。VueWrapper
是您组件实例的薄包装器。
请注意,像 find
这样的方法返回一个 DOMWrapper
,它是您组件及其子级中 DOM 节点的薄包装器。两者都实现了类似的 API。
attributes
返回 DOM 节点上的属性。
签名
attributes(): { [key: string]: string }
attributes(key: string): string
attributes(key?: string): { [key: string]: string } | string
详情
Component.vue
:
<template>
<div id="foo" :class="className" />
</template>
<script>
export default {
data() {
return {
className: 'bar'
}
}
}
</script>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('attributes', () => {
const wrapper = mount(Component)
expect(wrapper.attributes('id')).toBe('foo')
expect(wrapper.attributes('class')).toBe('bar')
})
classes
签名
classes(): string[]
classes(className: string): boolean
classes(className?: string): string[] | boolean
详情
返回元素上的类数组。
Component.vue
:
<template>
<span class="my-span" />
</template>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('classes', () => {
const wrapper = mount(Component)
expect(wrapper.classes()).toContain('my-span')
expect(wrapper.classes('my-span')).toBe(true)
expect(wrapper.classes('not-existing')).toBe(false)
})
emitted
返回组件发出的所有事件。
签名
emitted<T = unknown>(): Record<string, T[]>
emitted<T = unknown>(eventName: string): undefined | T[]
emitted<T = unknown>(eventName?: string): undefined | T[] | Record<string, T[]>
详情
参数存储在数组中,因此您可以验证每个事件发出了哪些参数。
Component.vue
:
<script>
export default {
created() {
this.$emit('greet', 'hello')
this.$emit('greet', 'goodbye')
}
}
</script>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('emitted', () => {
const wrapper = mount(Component)
// wrapper.emitted() equals to { greet: [ ['hello'], ['goodbye'] ] }
expect(wrapper.emitted()).toHaveProperty('greet')
expect(wrapper.emitted().greet).toHaveLength(2)
expect(wrapper.emitted().greet[0]).toEqual(['hello'])
expect(wrapper.emitted().greet[1]).toEqual(['goodbye'])
})
exists
验证元素是否存在。
签名
exists(): boolean
详情
您可以使用 querySelector
实现的相同语法。
Component.vue
:
<template>
<span />
</template>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('exists', () => {
const wrapper = mount(Component)
expect(wrapper.find('span').exists()).toBe(true)
expect(wrapper.find('p').exists()).toBe(false)
})
find
查找元素并返回一个 DOMWrapper
(如果找到)。
签名
find<K extends keyof HTMLElementTagNameMap>(selector: K): DOMWrapper<HTMLElementTagNameMap[K]>
find<K extends keyof SVGElementTagNameMap>(selector: K): DOMWrapper<SVGElementTagNameMap[K]>
find<T extends Element>(selector: string): DOMWrapper<T>
find(selector: string): DOMWrapper<Element>
find<T extends Node = Node>(selector: string | RefSelector): DOMWrapper<T>;
详情
您可以使用 querySelector
实现的相同语法。find
基本上是 querySelector
的别名。此外,您可以搜索元素引用。
它类似于 get
,但 find
如果未找到元素则返回一个 ErrorWrapper,而 get
将抛出错误。
一般来说,当您断言某物不存在时,始终使用 find
。如果您断言某物存在,请使用 get
。
Component.vue
:
<template>
<span>Span</span>
<span data-test="span">Span</span>
<span ref="span">Span</span>
</template>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('find', () => {
const wrapper = mount(Component)
wrapper.find('span') //=> found; returns DOMWrapper
wrapper.find('[data-test="span"]') //=> found; returns DOMWrapper
wrapper.find({ ref: 'span' }) //=> found; returns DOMWrapper
wrapper.find('p') //=> nothing found; returns ErrorWrapper
})
findAll
类似于 find
,但返回一个 DOMWrapper
数组。
签名
findAll<K extends keyof HTMLElementTagNameMap>(selector: K): DOMWrapper<HTMLElementTagNameMap[K]>[]
findAll<K extends keyof SVGElementTagNameMap>(selector: K): DOMWrapper<SVGElementTagNameMap[K]>[]
findAll<T extends Element>(selector: string): DOMWrapper<T>[]
findAll(selector: string): DOMWrapper<Element>[]
详情
Component.vue
:
<template>
<span v-for="number in [1, 2, 3]" :key="number" data-test="number">
{{ number }}
</span>
</template>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import BaseTable from './BaseTable.vue'
test('findAll', () => {
const wrapper = mount(BaseTable)
// .findAll() returns an array of DOMWrappers
const thirdRow = wrapper.findAll('span')[2]
})
findComponent
查找 Vue 组件实例并返回一个 VueWrapper
(如果找到)。否则返回 ErrorWrapper
。
签名
findComponent<T extends never>(selector: string): WrapperLike
findComponent<T extends DefinedComponent>(selector: T | Exclude<FindComponentSelector, FunctionalComponent>): VueWrapper<InstanceType<T>>
findComponent<T extends FunctionalComponent>(selector: T | string): DOMWrapper<Element>
findComponent<T extends never>(selector: NameSelector | RefSelector): VueWrapper
findComponent<T extends ComponentPublicInstance>(selector: T | FindComponentSelector): VueWrapper<T>
findComponent(selector: FindComponentSelector): WrapperLike
详情
findComponent
支持多种语法
语法 | 示例 | 详情 |
---|---|---|
querySelector | findComponent('.component') | 匹配标准查询选择器。 |
组件名称 | findComponent({name: 'a'}) | 匹配 PascalCase、snake-case、camelCase |
组件 ref | findComponent({ref: 'ref'}) | 只能用于已挂载组件的直接 ref 子元素 |
SFC | findComponent(Component) | 直接传递导入的组件 |
Foo.vue
<template>
<div class="foo">Foo</div>
</template>
<script>
export default {
name: 'Foo'
}
</script>
Component.vue
:
<template>
<Foo data-test="foo" ref="foo" class="foo" />
</template>
<script>
import Foo from '@/Foo'
export default {
components: { Foo }
}
</script>
Component.spec.js
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
import Foo from '@/Foo.vue'
test('findComponent', () => {
const wrapper = mount(Component)
// All the following queries would return a VueWrapper
wrapper.findComponent('.foo')
wrapper.findComponent('[data-test="foo"]')
wrapper.findComponent({ name: 'Foo' })
wrapper.findComponent({ ref: 'foo' })
wrapper.findComponent(Foo)
})
警告
如果组件中的 ref
指向 HTML 元素,findComponent
将返回空包装器。这是预期的行为。
与 CSS 选择器一起使用
使用 CSS 选择器与 findComponent
一起使用可能会导致令人困惑的行为
考虑以下示例
const ChildComponent = {
name: 'Child',
template: '<div class="child"></div>'
}
const RootComponent = {
name: 'Root',
components: { ChildComponent },
template: '<child-component class="root" />'
}
const wrapper = mount(RootComponent)
const rootByCss = wrapper.findComponent('.root') // => finds Root
expect(rootByCss.vm.$options.name).toBe('Root')
const childByCss = wrapper.findComponent('.child')
expect(childByCss.vm.$options.name).toBe('Root') // => still Root
这种行为的原因是 RootComponent
和 ChildComponent
共享相同的 DOM 节点,并且每个唯一的 DOM 节点只包含第一个匹配的组件
使用 CSS 选择器时的 WrapperLike 类型
例如,当使用 wrapper.findComponent('.foo')
时,VTU 将返回 WrapperLike
类型。这是因为函数式组件需要一个 DOMWrapper
,否则需要一个 VueWrapper
。您可以通过提供正确的组件类型来强制返回 VueWrapper
wrapper.findComponent('.foo') // returns WrapperLike
wrapper.findComponent<typeof FooComponent>('.foo') // returns VueWrapper
wrapper.findComponent<DefineComponent>('.foo') // returns VueWrapper
findAllComponents
签名
findAllComponents<T extends never>(selector: string): WrapperLike[]
findAllComponents<T extends DefinedComponent>(selector: T | Exclude<FindAllComponentsSelector, FunctionalComponent>): VueWrapper<InstanceType<T>>[]
findAllComponents<T extends FunctionalComponent>(selector: string): DOMWrapper<Element>[]
findAllComponents<T extends FunctionalComponent>(selector: T): DOMWrapper<Node>[]
findAllComponents<T extends never>(selector: NameSelector): VueWrapper[]
findAllComponents<T extends ComponentPublicInstance>(selector: T | FindAllComponentsSelector): VueWrapper<T>[]
findAllComponents(selector: FindAllComponentsSelector): WrapperLike[]
详情
类似于 findComponent
,但查找所有匹配查询的 Vue 组件实例。返回一个 VueWrapper
数组。
警告
findAllComponents
不支持 ref
语法。所有其他查询语法都是有效的。
Component.vue
:
<template>
<FooComponent v-for="number in [1, 2, 3]" :key="number" data-test="number">
{{ number }}
</FooComponent>
</template>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('findAllComponents', () => {
const wrapper = mount(Component)
// Returns an array of VueWrapper
wrapper.findAllComponents('[data-test="number"]')
})
与 CSS 选择器一起使用
findAllComponents
与 findComponent 一起使用 CSS 选择器时具有相同的行为
get
获取一个元素并返回一个 DOMWrapper
(如果找到)。否则会抛出错误。
签名
get<K extends keyof HTMLElementTagNameMap>(selector: K): Omit<DOMWrapper<HTMLElementTagNameMap[K]>, 'exists'>
get<K extends keyof SVGElementTagNameMap>(selector: K): Omit<DOMWrapper<SVGElementTagNameMap[K]>, 'exists'>
get<T extends Element>(selector: string): Omit<DOMWrapper<T>, 'exists'>
get(selector: string): Omit<DOMWrapper<Element>, 'exists'>
详情
它类似于 find
,但如果找不到元素,get
会抛出错误,而 find
会返回一个 ErrorWrapper。
作为经验法则,始终使用 get
,除非您断言某些东西不存在。在这种情况下,使用 find
。
Component.vue
:
<template>
<span>Span</span>
</template>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('get', () => {
const wrapper = mount(Component)
wrapper.get('span') //=> found; returns DOMWrapper
expect(() => wrapper.get('.not-there')).toThrowError()
})
getComponent
获取一个 Vue 组件实例并返回一个 VueWrapper
(如果找到)。否则会抛出错误。
签名
getComponent<T extends ComponentPublicInstance>(selector: new () => T): Omit<VueWrapper<T>, 'exists'>
getComponent<T extends ComponentPublicInstance>(selector: { name: string } | { ref: string } | string): Omit<VueWrapper<T>, 'exists'>
getComponent<T extends ComponentPublicInstance>(selector: any): Omit<VueWrapper<T>, 'exists'>
详情
它类似于 findComponent
,但如果找不到 Vue 组件实例,getComponent
会抛出错误,而 findComponent
会返回一个 ErrorWrapper。
支持的语法
语法 | 示例 | 详情 |
---|---|---|
querySelector | getComponent('.component') | 匹配标准查询选择器。 |
组件名称 | getComponent({name: 'a'}) | 匹配 PascalCase、snake-case、camelCase |
组件 ref | getComponent({ref: 'ref'}) | 只能用于已挂载组件的直接 ref 子元素 |
SFC | getComponent(Component) | 直接传递导入的组件 |
Foo.vue
<template>
<div class="foo">Foo</div>
</template>
<script>
export default {
name: 'Foo'
}
</script>
Component.vue
:
<template>
<Foo />
</template>
<script>
import Foo from '@/Foo'
export default {
components: { Foo }
}
</script>
Component.spec.js
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
import Foo from '@/Foo.vue'
test('getComponent', () => {
const wrapper = mount(Component)
wrapper.getComponent({ name: 'foo' }) // returns a VueWrapper
wrapper.getComponent(Foo) // returns a VueWrapper
expect(() => wrapper.getComponent('.not-there')).toThrowError()
})
html
返回元素的 HTML。
默认情况下,输出将使用 js-beautify
进行格式化,以使快照更易读。使用 raw: true
选项接收未格式化的 html 字符串。
签名
html(): string
html(options?: { raw?: boolean }): string
详情
Component.vue
:
<template>
<div>
<p>Hello world</p>
</div>
</template>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('html', () => {
const wrapper = mount(Component)
expect(wrapper.html()).toBe(
'<div>\n' +
' <p>Hello world</p>\n' +
'</div>'
)
expect(wrapper.html({ raw: true })).toBe('<div><p>Hello world</p></div>')
})
isVisible
验证元素是否可见。
签名
isVisible(): boolean
详情
警告
isVisible()
仅在使用 attachTo
将包装器附加到 DOM 时才能正常工作
const Component = {
template: `<div v-show="false"><span /></div>`
}
test('isVisible', () => {
const wrapper = mount(Component, {
attachTo: document.body
});
expect(wrapper.find('span').isVisible()).toBe(false);
})
props
返回传递给 Vue 组件的 props。
签名
props(): { [key: string]: any }
props(selector: string): any
props(selector?: string): { [key: string]: any } | any
详情
Component.vue
:
export default {
name: 'Component',
props: {
truthy: Boolean,
object: Object,
string: String
}
}
<template>
<Component truthy :object="{}" string="string" />
</template>
<script>
import Component from '@/Component'
export default {
components: { Component }
}
</script>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('props', () => {
const wrapper = mount(Component, {
global: { stubs: ['Foo'] }
})
const foo = wrapper.getComponent({ name: 'Foo' })
expect(foo.props('truthy')).toBe(true)
expect(foo.props('object')).toEqual({})
expect(foo.props('notExisting')).toEqual(undefined)
expect(foo.props()).toEqual({
truthy: true,
object: {},
string: 'string'
})
})
提示
作为经验法则,针对传递的 prop 的效果(DOM 更新、发出的事件等)进行测试。这将使测试比简单地断言传递了 prop 更强大。
setData
更新组件内部数据。
签名
setData(data: Record<string, any>): Promise<void>
详情
setData
不允许设置组件中未定义的新属性。
警告
此外,请注意 setData
不会修改组合 API setup()
数据。
Component.vue
:
<template>
<div>Count: {{ count }}</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
}
}
</script>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('setData', async () => {
const wrapper = mount(Component)
expect(wrapper.html()).toContain('Count: 0')
await wrapper.setData({ count: 1 })
expect(wrapper.html()).toContain('Count: 1')
})
警告
您应该在调用 setData
时使用 await
,以确保 Vue 在您进行断言之前更新 DOM。
setProps
更新组件 props。
签名
setProps(props: Record<string, any>): Promise<void>
详情
Component.vue
:
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
props: ['message']
}
</script>
Component.spec.js
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('updates prop', async () => {
const wrapper = mount(Component, {
props: {
message: 'hello'
}
})
expect(wrapper.html()).toContain('hello')
await wrapper.setProps({ message: 'goodbye' })
expect(wrapper.html()).toContain('goodbye')
})
警告
您应该在调用 setProps
时使用 await
,以确保 Vue 在您进行断言之前更新 DOM。
setValue
在 DOM 元素上设置值。包括
<input>
type="checkbox"
和type="radio"
将被检测到,并将设置element.checked
。
<select>
<option>
将被检测到,并将设置element.selected
。
签名
setValue(value: unknown, prop?: string): Promise<void>
详情
Component.vue
:
<template>
<input type="text" v-model="text" />
<p>Text: {{ text }}</p>
<input type="checkbox" v-model="checked" />
<div v-if="checked">The input has been checked!</div>
<select v-model="multiselectValue" multiple>
<option value="value1"></option>
<option value="value2"></option>
<option value="value3"></option>
</select>
</template>
<script>
export default {
data() {
return {
text: '',
checked: false,
multiselectValue: []
}
}
}
</script>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('setValue on checkbox', async () => {
const wrapper = mount(Component)
await wrapper.find('input[type="checkbox"]').setValue(true)
expect(wrapper.find('div')).toBe(true)
await wrapper.find('input[type="checkbox"]').setValue(false)
expect(wrapper.find('div')).toBe(false)
})
test('setValue on input text', async () => {
const wrapper = mount(Component)
await wrapper.find('input[type="text"]').setValue('hello!')
expect(wrapper.find('p').text()).toBe('Text: hello!')
})
test('setValue on multi select', async () => {
const wrapper = mount(Component)
// For select without multiple
await wrapper.find('select').setValue('value1')
// For select with multiple
await wrapper.find('select').setValue(['value1', 'value3'])
})
警告
您应该在调用 setValue
时使用 await
,以确保 Vue 在您进行断言之前更新 DOM。
text
返回元素的文本内容。
签名
text(): string
详情
Component.vue
:
<template>
<p>Hello world</p>
</template>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('text', () => {
const wrapper = mount(Component)
expect(wrapper.find('p').text()).toBe('Hello world')
})
trigger
触发 DOM 事件,例如 click
、submit
或 keyup
。
签名
interface TriggerOptions {
code?: String
key?: String
keyCode?: Number
[custom: string]: any
}
trigger(eventString: string, options?: TriggerOptions | undefined): Promise<void>
详情
Component.vue
:
<template>
<span>Count: {{ count }}</span>
<button @click="count++">Click me</button>
</template>
<script>
export default {
data() {
return {
count: 0
}
}
}
</script>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('trigger', async () => {
const wrapper = mount(Component)
await wrapper.find('button').trigger('click')
expect(wrapper.find('span').text()).toBe('Count: 1')
})
请注意,trigger
接受第二个参数以将选项传递给触发的事件
await wrapper.trigger('keydown', { keyCode: 65 })
警告
您应该在调用 trigger
时使用 await
,以确保 Vue 在您进行断言之前更新 DOM。
警告
某些事件(例如单击复选框以更改其 v-model
)仅在测试使用 attachTo: document.body
时才有效。否则,将不会触发 change
事件,并且 v-model
值不会更改。
unmount
从 DOM 中卸载应用程序。
签名
unmount(): void
详情
它仅在从 mount
返回的根 VueWrapper
上有效。在测试后用于手动清理。
Component.vue
:
<script>
export default {
unmounted() {
console.log('unmounted!')
}
}
</script>
Component.spec.js
:
import { mount } from '@vue/test-utils'
import Component from './Component.vue'
test('unmount', () => {
const wrapper = mount(Component)
wrapper.unmount()
// Component is removed from DOM.
// console.log has been called with 'unmounted!'
})
包装器属性
vm
签名
vm: ComponentPublicInstance
详情
Vue
应用程序实例。您可以访问所有 实例方法 和 实例属性。
请注意,vm
仅在 VueWrapper
上可用。
提示
作为经验法则,针对传递的 prop 的效果(DOM 更新、发出的事件等)进行测试。这将使测试比简单地断言传递了 prop 更强大。
shallowMount
创建一个包装器,其中包含已挂载和渲染的 Vue 组件以进行测试,所有子组件都被存根。
签名
interface MountingOptions<Props, Data = {}> {
attachTo?: Element | string
attrs?: Record<string, unknown>
data?: () => {} extends Data ? any : Data extends object ? Partial<Data> : any
props?: (RawProps & Props) | ({} extends Props ? null : never)
slots?: { [key: string]: Slot } & { default?: Slot }
global?: GlobalMountOptions
}
function shallowMount(Component, options?: MountingOptions): VueWrapper
详情
shallowMount
的行为与 mount
完全相同,但默认情况下它会存根所有子组件。本质上,shallowMount(Component)
是 mount(Component, { shallow: true })
的别名。
enableAutoUnmount
签名
enableAutoUnmount(hook: (callback: () => void) => void);
disableAutoUnmount(): void;
详情
enableAutoUnmount
允许自动销毁 Vue 包装器。销毁逻辑作为回调传递给 hook
函数。常见的用法是将 enableAutoUnmount
与测试框架提供的拆卸辅助函数(如 afterEach
)一起使用
import { enableAutoUnmount } from '@vue/test-utils'
enableAutoUnmount(afterEach)
如果您只想在测试套件的特定子集中使用此行为,并且想要显式禁用此行为,则 disableAutoUnmount
可能有用
flushPromises
签名
flushPromises(): Promise<unknown>
详情
flushPromises
刷新所有已解析的 promise 处理程序。这有助于确保异步操作(如 promise 或 DOM 更新)在您断言它们之前发生。
查看 执行 HTTP 请求 以查看 flushPromises
的示例。
config
config.global
签名
type GlobalMountOptions = {
plugins?: (Plugin | [Plugin, ...any[]])[]
config?: Partial<Omit<AppConfig, 'isNativeTag'>>
mixins?: ComponentOptions[]
mocks?: Record<string, any>
provide?: Record<any, any>
components?: Record<string, Component | object>
directives?: Record<string, Directive>
stubs?: Stubs = Record<string, boolean | Component> | Array<string>
renderStubDefaultSlot?: boolean
}
详情
您可以为整个测试套件配置挂载选项,而不是在每个测试的基础上配置它们。这些将在您每次 mount
组件时默认使用。如果需要,您可以在每个测试的基础上覆盖默认值。
示例
一个示例可能是全局模拟来自 vue-i18n 的 $t
变量和一个组件
Component.vue
:
<template>
<p>{{ $t('message') }}</p>
<my-component />
</template>
<script>
import MyComponent from '@/components/MyComponent'
export default {
components: {
MyComponent
}
}
</script>
Component.spec.js
:
import { config, mount } from '@vue/test-utils'
import { defineComponent } from 'vue'
const MyComponent = defineComponent({
template: `<div>My component</div>`
})
config.global.stubs = {
MyComponent
}
config.global.mocks = {
$t: (text) => text
}
test('config.global mocks and stubs', () => {
const wrapper = mount(Component)
expect(wrapper.html()).toBe('<p>message</p><div>My component</div>')
})
提示
请记住,此行为是全局的,而不是在每次挂载的基础上进行的。您可能需要在每次测试之前和之后启用/禁用它。
components
RouterLinkStub
一个组件,用于在您不想模拟或包含完整路由器时存根 Vue Router router-link
组件。
您可以使用此组件在渲染树中查找 router-link
组件。
用法
在挂载选项中设置为存根
import { mount, RouterLinkStub } from '@vue/test-utils'
const wrapper = mount(Component, {
global: {
stubs: {
RouterLink: RouterLinkStub,
},
},
})
expect(wrapper.findComponent(RouterLinkStub).props().to).toBe('/some/path')
与插槽一起使用
RouterLinkStub
组件支持插槽内容,并将为其插槽属性返回非常基本的值。如果您需要更具体的插槽属性值用于测试,请考虑使用 真实路由器,以便您可以使用真实的 router-link
组件。或者,您可以通过复制测试工具包中的实现来定义自己的 RouterLinkStub
组件。