Appearance
API 参考
¥API Reference
挂载
¥mount
创建一个 Wrapper,其中包含要测试的已挂载和渲染的 Vue 组件。请注意,当使用 Vitest 模拟日期/计时器时,必须在 vi.setSystemTime
之后调用。
¥Creates a Wrapper that contains the mounted and rendered Vue component to test. Note that when mocking dates/timers with Vitest, this must be called after vi.setSystemTime
.
签名:
¥Signature:
ts
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
细节:
¥Details:
mount
是 Vue Test Utils 暴露的主要方法。它创建一个 Vue 3 应用来保存并渲染正在测试的组件。作为返回,它创建一个封装器来对组件进行操作和断言。
¥mount
is the main method exposed by Vue Test Utils. It creates a Vue 3 app that holds and renders the Component under testing. In return, it creates a wrapper to act and assert against the Component.
js
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
接受第二个参数来定义组件的状态配置。
¥Notice that mount
accepts a second parameter to define the component's state configuration.
示例:使用组件 props 和 Vue App 插件挂载
¥Example : mounting with component props and a Vue App plugin
js
const wrapper = mount(Component, {
props: {
msg: 'world'
},
global: {
plugins: [vuex]
}
})
options.global
在组件状态中,你可以通过 MountingOptions.global
config property. 配置上述 Vue 3 应用,这对于提供组件期望可用的模拟值非常有用。
¥Among component state, you can configure the aformentioned Vue 3 app by the MountingOptions.global
config property. This would be useful for providing mocked values which your components expect to have available.
提示
如果你发现自己必须为许多测试设置通用应用配置,那么你可以使用导出的 config
对象。 为整个测试套件设置配置
¥If you find yourself having to set common App configuration for many of your tests, then you can set configuration for your entire test suite using the exported config
object.
attachTo
指定要挂载组件的节点。使用 renderToString
时此功能不可用。
¥Specify the node to mount the component on. This is not available when using renderToString
.
签名:
¥Signature:
ts
attachTo?: Element | string
细节:
¥Details:
可以是有效的 CSS 选择器,或连接到文档的 Element
。
¥Can be a valid CSS selector, or an Element
connected to the document.
请注意,组件附加到节点,它不会替换节点的全部内容。如果在多次测试中将组件挂载在同一个节点上 - 确保在每次测试后通过调用 wrapper.unmount()
卸载它,这将从节点中删除渲染的元素。
¥Note that the component is appended to the node, it doesn't replace the whole content of the node. If you mount the component on the same node in multiple tests - make sure to unmount it after each test by calling wrapper.unmount()
, this will remove the rendered elements from the node.
Component.vue
:
vue
<template>
<p>Vue Component</p>
</template>
Component.spec.js
:
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 属性。
¥Sets HTML attributes to component.
签名:
¥Signature:
ts
attrs?: Record<string, unknown>
细节:
¥Details:
Component.spec.js
:
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'
})
})
请注意,设置已定义的 prop 将始终胜过属性:
¥Notice that setting a defined prop will always trump an attribute:
js
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
。必须是一个函数。
¥Overrides a component's default data
. Must be a function.
签名:
¥Signature:
ts
data?: () => {} extends Data ? any : Data extends object ? Partial<Data> : any
细节:
¥Details:
Component.vue
vue
<template>
<div>Hello {{ message }}</div>
</template>
<script>
export default {
data() {
return {
message: 'everyone'
}
}
}
</script>
Component.spec.js
:
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
挂载时在组件上设置属性。
¥Sets props on a component when mounted.
签名:
¥Signature:
ts
props?: (RawProps & Props) | ({} extends Props ? null : never)
细节:
¥Details:
Component.vue
:
vue
<template>
<span>Count: {{ count }}</span>
</template>
<script>
export default {
props: {
count: {
type: Number,
required: true
}
}
}
</script>
Component.spec.js
:
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
设置组件上插槽的值。
¥Sets values for slots on a component.
签名:
¥Signature:
ts
type Slot = VNode | string | { render: Function } | Function | Component
slots?: { [key: string]: Slot } & { default?: Slot }
细节:
¥Details:
插槽可以是字符串或任何有效的组件定义,可以从 .vue
文件导入,也可以内联提供
¥Slots can be a string or any valid component definition either imported from a .vue
file or provided inline
Component.vue
:
vue
<template>
<slot name="first" />
<slot />
<slot name="second" />
</template>
Bar.vue
:
vue
<template>
<div>Bar</div>
</template>
Component.spec.js
:
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
签名:
¥Signature:
ts
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
选项。请参阅此处了解如何配置项目范围的默认值。
¥You can configure all the global
options on both a per test basis and also for the entire test suite. See here for how to configure project wide defaults.
global.components
将组件全局注册到已挂载的组件。
¥Registers components globally to the mounted component.
签名:
¥Signature:
ts
components?: Record<string, Component | object>
细节:
¥Details:
Component.vue
:
vue
<template>
<div>
<global-component />
</div>
</template>
<script>
import GlobalComponent from '@/components/GlobalComponent'
export default {
components: {
GlobalComponent
}
}
</script>
GlobalComponent.vue
:
vue
<template>
<div class="global-component">My Global Component</div>
</template>
Component.spec.js
:
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 的应用全局配置。
¥Configures Vue's application global configuration.
签名:
¥Signature:
ts
config?: Partial<Omit<AppConfig, 'isNativeTag'>>
global.directives
将 directive 全局注册到已挂载的组件。
¥Registers a directive globally to the mounted component.
签名:
¥Signature:
ts
directives?: Record<string, Directive>
细节:
¥Details:
Component.spec.js
:
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
将 mixin 全局注册到已挂载的组件。
¥Registers a mixin globally to the mounted component.
签名:
¥Signature:
ts
mixins?: ComponentOptions[]
细节:
¥Details:
Component.spec.js
:
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 a global instance property. Can be used for mocking out this.$store
, this.$router
etc.
签名:
¥Signature:
ts
mocks?: Record<string, any>
细节:
¥Details:
警告
这是为了模拟由第三方插件注入的变量,而不是 Vue 的原生属性,例如 $root、$children 等。
¥This is designed to mock variables injected by third party plugins, not Vue's native properties such as $root, $children, etc.
Component.vue
:
vue
<template>
<button @click="onClick" />
</template>
<script>
export default {
methods: {
onClick() {
this.$store.dispatch('click')
}
}
}
</script>
Component.spec.js
:
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
在已挂载的组件上挂载插件。
¥Installs plugins on the mounted component.
签名:
¥Signature:
ts
plugins?: (Plugin | [Plugin, ...any[]])[]
细节:
¥Details:
Component.spec.js
:
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]
}
})
})
要使用带选项的插件,可以传递选项数组。
¥To use plugin with options, an array of options can be passed.
Component.spec.js
:
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
功能中接收的数据。
¥Provides data to be received in a setup
function via inject
.
签名:
¥Signature:
ts
provide?: Record<any, any>
细节:
¥Details:
Component.vue
:
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
:
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
作为提供密钥,则可以将其用作动态密钥:
¥If you are using a ES6 Symbol
for your provide key, you can use it as a dynamic key:
Component.spec.js
:
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
时也是如此。
¥Renders the default
slot content, even when using shallow
or shallowMount
.
签名:
¥Signature:
ts
renderStubDefaultSlot?: boolean
细节:
¥Details:
默认为 false。
¥Defaults to false.
Component.vue
vue
<template>
<slot />
<another-component />
</template>
<script>
export default {
components: {
AnotherComponent
}
}
</script>
AnotherComponent.vue
vue
<template>
<p>Another component content</p>
</template>
Component.spec.js
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>'
)
})
由于技术限制,此行为无法扩展到默认插槽以外的插槽。
¥Due to technical limitations, this behavior cannot be extended to slots other than the default one.
global.stubs
在已挂载的组件上设置全局存根。
¥Sets a global stub on the mounted component.
签名:
¥Signature:
ts
stubs?: Record<any, any>
细节:
¥Details:
它默认存根 Transition
和 TransitionGroup
。
¥It stubs Transition
and TransitionGroup
by default.
Component.vue
:
vue
<template>
<div><foo /></div>
</template>
<script>
import Foo from '@/Foo.vue'
export default {
components: { Foo }
}
</script>
Component.spec.js
:
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
从组件中删除所有子组件。
¥Stubs out all child components from the component.
签名:
¥Signature:
ts
shallow?: boolean
细节:
¥Details:
默认为 false。
¥Defaults to false.
Component.vue
vue
<template>
<a-component />
<another-component />
</template>
<script>
export default {
components: {
AComponent,
AnotherComponent
}
}
</script>
Component.spec.js
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
挂载组件的别名。
¥shallowMount()
is an alias to mounting a component with shallow: true
.
封装方法
¥Wrapper methods
当你使用 mount
时,会返回 VueWrapper
,其中包含许多有用的测试方法。VueWrapper
是组件实例的薄封装。
¥When you use mount
, a VueWrapper
is returned with a number of useful methods for testing. A VueWrapper
is a thin wrapper around your component instance.
请注意,像 find
这样的方法会返回 DOMWrapper
,它是组件及其子组件中 DOM 节点的薄封装器。两者都实现了类似的 API。
¥Notice that methods like find
return a DOMWrapper
, which is a thin wrapper around the DOM nodes in your component and its children. Both implement a similar API.
attributes
返回 DOM 节点上的属性。
¥Returns attributes on a DOM node.
签名:
¥Signature:
ts
attributes(): { [key: string]: string }
attributes(key: string): string
attributes(key?: string): { [key: string]: string } | string
细节:
¥Details:
Component.vue
:
vue
<template>
<div id="foo" :class="className" />
</template>
<script>
export default {
data() {
return {
className: 'bar'
}
}
}
</script>
Component.spec.js
:
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
签名:
¥Signature:
ts
classes(): string[]
classes(className: string): boolean
classes(className?: string): string[] | boolean
细节:
¥Details:
返回元素上的类数组。
¥Returns an array of classes on an element.
Component.vue
:
vue
<template>
<span class="my-span" />
</template>
Component.spec.js
:
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
返回组件触发的所有事件。
¥Returns all the emitted events from the Component.
签名:
¥Signature:
ts
emitted<T = unknown>(): Record<string, T[]>
emitted<T = unknown>(eventName: string): undefined | T[]
emitted<T = unknown>(eventName?: string): undefined | T[] | Record<string, T[]>
细节:
¥Details:
参数存储在数组中,因此你可以验证随每个事件一起触发的参数。
¥The arguments are stored in an array, so you can verify which arguments were emitted along with each event.
Component.vue
:
vue
<script>
export default {
created() {
this.$emit('greet', 'hello')
this.$emit('greet', 'goodbye')
}
}
</script>
Component.spec.js
:
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
验证元素是否存在。
¥Verify whether an element exists or not.
签名:
¥Signature:
ts
exists(): boolean
细节:
¥Details:
你可以使用 querySelector
实现的相同语法。
¥You can use the same syntax querySelector
implements.
Component.vue
:
vue
<template>
<span />
</template>
Component.spec.js
:
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
。
¥Finds an element and returns a DOMWrapper
if one is found.
签名:
¥Signature:
ts
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>;
细节:
¥Details:
你可以使用 querySelector
实现的相同语法。find
基本上是 querySelector
的别名。此外,你还可以搜索元素引用。
¥You can use the same syntax querySelector
implements. find
is basically an alias for querySelector
. In addition you can search for element refs.
它类似于 get
,但如果未找到元素,find
将返回 ErrorWrapper,而 get
将抛出错误。
¥It is similar to get
, but find
returns an ErrorWrapper if an element is not found while get
will throw an error.
根据经验,当你断言某物不存在时,请始终使用 find
。如果你断言某物确实存在,请使用 get
。
¥As a rule of thumb, always use find
when you are asserting something doesn't exist. If you are asserting something does exist, use get
.
Component.vue
:
vue
<template>
<span>Span</span>
<span data-test="span">Span</span>
<span ref="span">Span</span>
</template>
Component.spec.js
:
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
的数组。
¥Similar to find
, but instead returns an array of DOMWrapper
.
签名:
¥Signature:
ts
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>[]
细节:
¥Details:
Component.vue
:
vue
<template>
<span v-for="number in [1, 2, 3]" :key="number" data-test="number">
{{ number }}
</span>
</template>
Component.spec.js
:
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
。
¥Finds a Vue Component instance and returns a VueWrapper
if found. Returns ErrorWrapper
otherwise.
签名:
¥Signature:
ts
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
细节:
¥Details:
findComponent
支持多种语法:
¥findComponent
supports several syntaxes:
syntax | example | details |
---|---|---|
querySelector | findComponent('.component') | 匹配标准查询选择器。 |
组件名称 | findComponent({name: 'a'}) | 匹配 PascalCase、snake-case、camelCase |
组件参考 | findComponent({ref: 'ref'}) | 只能用于已挂载组件的直接引用子级 |
SFC | findComponent(Component) | 直接传递导入的组件 |
Foo.vue
vue
<template>
<div class="foo">Foo</div>
</template>
<script>
export default {
name: 'Foo'
}
</script>
Component.vue
:
vue
<template>
<Foo data-test="foo" ref="foo" class="foo" />
</template>
<script>
import Foo from '@/Foo'
export default {
components: { Foo }
}
</script>
Component.spec.js
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
将返回空封装器。这是预期行为。
¥If ref
in component points to HTML element, findComponent
will return empty wrapper. This is intended behaviour.
与 CSS 选择器一起使用
将 findComponent
与 CSS 选择器一起使用可能会产生令人困惑的行为
¥Using findComponent
with CSS selector might have confusing behavior
考虑这个例子:
¥Consider this example:
js
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 节点仅包含第一个匹配组件
¥The reason for such behavior is that RootComponent
and ChildComponent
are sharing same DOM node and only first matching component is included for each unique DOM node
使用 CSS 选择器时的 WrapperLike 类型
例如,当使用 wrapper.findComponent('.foo')
时,VTU 将返回 WrapperLike
类型。这是因为功能组件需要 DOMWrapper
,否则需要 VueWrapper
。你可以通过提供正确的组件类型强制返回 VueWrapper
:
¥When using wrapper.findComponent('.foo')
for example then VTU will return the WrapperLike
type. This is because functional components would need a DOMWrapper
otherwise a VueWrapper
. You can force to return a VueWrapper
by providing the correct component type:
typescript
wrapper.findComponent('.foo') // returns WrapperLike
wrapper.findComponent<typeof FooComponent>('.foo') // returns VueWrapper
wrapper.findComponent<DefineComponent>('.foo') // returns VueWrapper
findAllComponents
签名:
¥Signature:
ts
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[]
细节:
¥Details:
与 findComponent
类似,但查找与查询匹配的所有 Vue 组件实例。返回 VueWrapper
的数组。
¥Similar to findComponent
but finds all Vue Component instances that match the query. Returns an array of VueWrapper
.
警告
findAllComponents
不支持 ref
语法。所有其他查询语法都是有效的。
¥ref
syntax is not supported in findAllComponents
. All other query syntaxes are valid.
Component.vue
:
vue
<template>
<FooComponent v-for="number in [1, 2, 3]" :key="number" data-test="number">
{{ number }}
</FooComponent>
</template>
Component.spec.js
:
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 选择器一起使用
与 CSS 选择器一起使用时,findAllComponents
具有与 findComponent 相同的行为
¥findAllComponents
has same behavior when used with CSS selector as findComponent
get
获取一个元素,如果找到则返回 DOMWrapper
。否则会抛出错误。
¥Gets an element and returns a DOMWrapper
if found. Otherwise it throws an error.
签名:
¥Signature:
ts
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'>
细节:
¥Details:
它与 find
类似,但 get
如果未找到元素,则会抛出错误,而 find
将返回 ErrorWrapper。
¥It is similar to find
, but get
throws an error if an element is not found while find
will return an ErrorWrapper.
根据经验,除非你断言某些内容不存在,否则始终使用 get
。在这种情况下,请使用 find
。
¥As a rule of thumb, always use get
except when you are asserting something doesn't exist. In that case use find
.
Component.vue
:
vue
<template>
<span>Span</span>
</template>
Component.spec.js
:
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
。否则会抛出错误。
¥Gets a Vue Component instance and returns a VueWrapper
if found. Otherwise it throws an error.
签名:
¥Signature:
ts
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'>
细节:
¥Details:
它类似于 findComponent
,但如果未找到 Vue 组件实例,getComponent
将抛出错误,而 findComponent
将返回 ErrorWrapper。
¥It is similar to findComponent
, but getComponent
throws an error if a Vue Component instance is not found while findComponent
will return an ErrorWrapper.
支持的语法:
¥Supported syntax:
syntax | example | details |
---|---|---|
querySelector | getComponent('.component') | 匹配标准查询选择器。 |
组件名称 | getComponent({name: 'a'}) | 匹配 PascalCase、snake-case、camelCase |
组件参考 | getComponent({ref: 'ref'}) | 只能用于已挂载组件的直接引用子级 |
SFC | getComponent(Component) | 直接传递导入的组件 |
Foo.vue
vue
<template>
<div class="foo">Foo</div>
</template>
<script>
export default {
name: 'Foo'
}
</script>
Component.vue
:
vue
<template>
<Foo />
</template>
<script>
import Foo from '@/Foo'
export default {
components: { Foo }
}
</script>
Component.spec.js
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。
¥Returns the HTML of an element.
默认情况下,输出格式为 js-beautify
,以使快照更具可读性。使用 raw: true
选项接收未格式化的 html 字符串。
¥By default the output is formatted with js-beautify
to make snapshots more readable. Use raw: true
option to receive the unformatted html string.
签名:
¥Signature:
ts
html(): string
html(options?: { raw?: boolean }): string
细节:
¥Details:
Component.vue
:
vue
<template>
<div>
<p>Hello world</p>
</div>
</template>
Component.spec.js
:
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
验证元素是否可见。
¥Verify whether an element is visible or not.
签名:
¥Signature:
ts
isVisible(): boolean
细节:
¥Details:
警告
仅当使用 attachTo
将封装器附加到 DOM 时,isVisible()
才能正常工作
¥isVisible()
only works correctly if the wrapper is attached to the DOM using attachTo
js
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。
¥Returns props passed to a Vue Component.
签名:
¥Signature:
ts
props(): { [key: string]: any }
props(selector: string): any
props(selector?: string): { [key: string]: any } | any
细节:
¥Details:
Component.vue
:
js
export default {
name: 'Component',
props: {
truthy: Boolean,
object: Object,
string: String
}
}
vue
<template>
<Component truthy :object="{}" string="string" />
</template>
<script>
import Component from '@/Component'
export default {
components: { Component }
}
</script>
Component.spec.js
:
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 通过更强大。
¥As a rule of thumb, test against the effects of a passed prop (a DOM update, an emitted event, and so on). This will make tests more powerful than simply asserting that a prop is passed.
setData
更新组件内部数据。
¥Updates component internal data.
签名:
¥Signature:
ts
setData(data: Record<string, any>): Promise<void>
细节:
¥Details:
setData
不允许设置组件中未定义的新属性。
¥setData
does not allow setting new properties that are not defined in the component.
警告
另请注意,setData
不会修改合成 API setup()
数据。
¥Also, notice that setData
does not modify composition API setup()
data.
Component.vue
:
vue
<template>
<div>Count: {{ count }}</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
}
}
</script>
Component.spec.js
:
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。
¥You should use await
when you call setData
to ensure that Vue updates the DOM before you make an assertion.
setProps
更新组件属性。
¥Updates component props.
签名:
¥Signature:
ts
setProps(props: Record<string, any>): Promise<void>
细节:
¥Details:
Component.vue
:
vue
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
props: ['message']
}
</script>
Component.spec.js
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。
¥You should use await
when you call setProps
to ensure that Vue updates the DOM before you make an assertion.
setValue
在 DOM 元素上设置一个值。包括:
¥Sets a value on DOM element. Including:
<input>
检测到
type="checkbox"
和type="radio"
并将设置element.checked
。¥
type="checkbox"
andtype="radio"
are detected and will haveelement.checked
set.
<select>
检测到
<option>
并将设置element.selected
。¥
<option>
is detected and will haveelement.selected
set.
签名:
¥Signature:
ts
setValue(value: unknown, prop?: string): Promise<void>
细节:
¥Details:
Component.vue
:
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
:
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。
¥You should use await
when you call setValue
to ensure that Vue updates the DOM before you make an assertion.
text
返回元素的文本内容。
¥Returns the text content of an element.
签名:
¥Signature:
ts
text(): string
细节:
¥Details:
Component.vue
:
vue
<template>
<p>Hello world</p>
</template>
Component.spec.js
:
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
。
¥Triggers a DOM event, for example click
, submit
or keyup
.
签名:
¥Signature:
ts
interface TriggerOptions {
code?: String
key?: String
keyCode?: Number
[custom: string]: any
}
trigger(eventString: string, options?: TriggerOptions | undefined): Promise<void>
细节:
¥Details:
Component.vue
:
vue
<template>
<span>Count: {{ count }}</span>
<button @click="count++">Click me</button>
</template>
<script>
export default {
data() {
return {
count: 0
}
}
}
</script>
Component.spec.js
:
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
接受第二个参数以将选项传递给触发的事件:
¥Note that trigger
accepts a second argument to pass options to the triggered Event:
js
await wrapper.trigger('keydown', { keyCode: 65 })
警告
调用 trigger
时应该使用 await
,以确保 Vue 在做出断言之前更新 DOM。
¥You should use await
when you call trigger
to ensure that Vue updates the DOM before you make an assertion.
警告
有些事件(例如单击复选框以更改其 v-model
)仅在测试使用 attachTo: document.body
时才有效。否则,change
事件不会被触发,v-model
值不会改变。
¥Some events, like clicking on a checkbox to change its v-model
, will only work if the test uses attachTo: document.body
. Otherwise, the change
event will not be triggered, and the v-model
value does not change.
unmount
从 DOM 卸载应用。
¥Unmount the application from the DOM.
签名:
¥Signature:
ts
unmount(): void
细节:
¥Details:
它仅适用于从 mount
返回的根 VueWrapper
。对于测试后的手动清理很有用。
¥It only works on the root VueWrapper
returned from mount
. Useful for manual clean-up after tests.
Component.vue
:
vue
<script>
export default {
unmounted() {
console.log('unmounted!')
}
}
</script>
Component.spec.js
:
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!'
})
封装属性
¥Wrapper properties
vm
签名:
¥Signature:
ts
vm: ComponentPublicInstance
细节:
¥Details:
¥The Vue
app instance. You can access all of the instance methods and instance properties.
请注意,vm
仅适用于 VueWrapper
。
¥Notice that vm
is only available on a VueWrapper
.
提示
根据经验,测试传递的 prop(DOM 更新、触发的事件等)的效果。这将使测试比简单地断言 prop 通过更强大。
¥As a rule of thumb, test against the effects of a passed prop (a DOM update, an emitted event, and so on). This will make tests more powerful than simply asserting that a prop is passed.
shallowMount
创建一个包含已挂载和渲染的 Vue 组件的封装器,以测试所有子组件的存根。
¥Creates a Wrapper that contains the mounted and rendered Vue component to test with all children stubbed out.
签名:
¥Signature:
ts
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
细节:
¥Details:
shallowMount
的行为与 mount
完全相同,但它默认存根所有子组件。本质上,shallowMount(Component)
是 mount(Component, { shallow: true })
的别名。
¥shallowMount
behaves exactly like mount
, but it stubs all child components by default. Essentially, shallowMount(Component)
is an alias of mount(Component, { shallow: true })
.
enableAutoUnmount
签名:
¥Signature:
ts
enableAutoUnmount(hook: (callback: () => void) => void);
disableAutoUnmount(): void;
细节:
¥Details:
enableAutoUnmount
允许自动销毁 Vue 封装器。销毁逻辑作为回调传递给 hook
函数。常见用法是将 enableAutoUnmount
与测试框架提供的拆卸辅助函数一起使用,例如 afterEach
:
¥enableAutoUnmount
allows to automatically destroy Vue wrappers. Destroy logic is passed as callback to hook
Function. Common usage is to use enableAutoUnmount
with teardown helper functions provided by your test framework, such as afterEach
:
ts
import { enableAutoUnmount } from '@vue/test-utils'
enableAutoUnmount(afterEach)
如果你只希望在测试套件的特定子集中出现此行为并且希望显式禁用此行为,则 disableAutoUnmount
可能很有用
¥disableAutoUnmount
might be useful if you want this behavior only in specific subset of your test suite and you want to explicitly disable this behavior
flushPromises
签名:
¥Signature:
ts
flushPromises(): Promise<unknown>
细节:
¥Details:
flushPromises
刷新所有已解决的 promise 处理程序。这有助于确保异步操作(例如 Promise 或 DOM 更新)在对其进行断言之前已经发生。
¥flushPromises
flushes all resolved promise handlers. This helps make sure async operations such as promises or DOM updates have happened before asserting against them.
查看 触发 HTTP 请求 以查看 flushPromises
的实际示例。
¥Check out Making HTTP requests to see an example of flushPromises
in action.
配置
¥config
config.global
签名:
¥Signature:
ts
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
}
细节:
¥Details:
你可以为整个测试套件配置挂载选项,而不是为每个测试配置挂载选项。每次 mount
组件时都会默认使用这些。如果需要,你可以在每次测试的基础上覆盖默认值。
¥Instead of configuring mounting options on a per test basis, you can configure them for your entire test suite. These will be used by default every time you mount
a component. If desired, you can then override your defaults on a per test basis.
例子 :
¥Example :
一个示例可能是全局模拟 vue-i18n 和组件中的 $t
变量:
¥An example might be globally mocking the $t
variable from vue-i18n and a component:
Component.vue
:
vue
<template>
<p>{{ $t('message') }}</p>
<my-component />
</template>
<script>
import MyComponent from '@/components/MyComponent'
export default {
components: {
MyComponent
}
}
</script>
Component.spec.js
:
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>')
})
提示
请记住,此行为是全局的,而不是逐个挂载的。你可能需要在每次测试之前和之后启用/禁用它。
¥Remember that this behavior is global, not on a mount by mount basis. You might need to enable/disable it before and after each test.
组件
¥components
RouterLinkStub
当你不想模拟或包含完整路由时,用于存根 Vue Router router-link
组件的组件。
¥A component to stub the Vue Router router-link
component when you don't want to mock or include a full router.
你可以使用此组件在渲染树中查找 router-link
组件。
¥You can use this component to find a router-link
component in the render tree.
用法:
¥Usage:
在挂载选项中设置为存根:
¥Set as a stub in the mounting options:
js
import { mount, RouterLinkStub } from '@vue/test-utils'
const wrapper = mount(Component, {
global: {
stubs: {
RouterLink: RouterLinkStub,
},
},
})
expect(wrapper.findComponent(RouterLinkStub).props().to).toBe('/some/path')
与插槽一起使用:
¥Usage with slot:
RouterLinkStub
组件支持插槽内容,并将为其插槽属性返回非常基本的值。如果你的测试需要更具体的 slot prop 值,请考虑使用 真正的路由,以便你可以使用真正的 router-link
组件。或者,你可以通过从 test-utils 包复制实现来定义你自己的 RouterLinkStub
组件。
¥The RouterLinkStub
component supports slot content and will return very basic values for its slot props. If you need more specific slot prop values for your tests, consider using a real router so you can use a real router-link
component. Alternatively, you can define your own RouterLinkStub
component by copying the implementation from the test-utils package.