From 6d84190b7adab983aa7c522349ff59cadc24072c Mon Sep 17 00:00:00 2001 From: wuzhiqing Date: Wed, 20 Nov 2024 06:49:42 +0000 Subject: [PATCH 01/16] feat: add zh config --- docs/.vitepress/config/index.mts | 4 +- docs/.vitepress/config/zh.mts | 154 +++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 docs/.vitepress/config/zh.mts diff --git a/docs/.vitepress/config/index.mts b/docs/.vitepress/config/index.mts index 6965cc2eb..ad9c16ffe 100644 --- a/docs/.vitepress/config/index.mts +++ b/docs/.vitepress/config/index.mts @@ -1,5 +1,6 @@ import { enConfig } from './en.mts' import { frConfig } from './fr.mts' +import { zhConfig } from './zh.mts' import { sharedConfig } from './shared.mts' import { defineConfig } from 'vitepress' @@ -8,6 +9,7 @@ export default defineConfig({ locales: { root: { label: 'English', lang: 'en-US', link: '/', ...enConfig }, - fr: { label: 'Français', lang: 'fr-FR', link: '/fr/', ...frConfig }, + fr: { label: 'Français', lang: 'fr-FR', link: '/fr/', ...frConfig }, + zh: { label: '简体中文', lang: 'zh-CN', link: '/zh/', ...zhConfig } } }) diff --git a/docs/.vitepress/config/zh.mts b/docs/.vitepress/config/zh.mts new file mode 100644 index 000000000..3e3b0d194 --- /dev/null +++ b/docs/.vitepress/config/zh.mts @@ -0,0 +1,154 @@ +import type { DefaultTheme, LocaleSpecificConfig } from 'vitepress' + +export const META_URL = '' +export const META_TITLE = 'Vue Test Utils' +export const META_DESCRIPTION = 'Vue.js 3 官方测试工具集' + +export const zhConfig: LocaleSpecificConfig = { + description: META_DESCRIPTION, + head: [ + ['meta', { property: 'og:url', content: META_URL }], + ['meta', { property: 'og:title', content: META_TITLE }], + ['meta', { property: 'og:description', content: META_DESCRIPTION }], + ['meta', { property: 'twitter:url', content: META_URL }], + ['meta', { property: 'twitter:title', content: META_TITLE }], + ['meta', { property: 'twitter:description', content: META_DESCRIPTION }] + ], + + themeConfig: { + editLink: { + pattern: 'https://github.com/vuejs/test-utils/edit/main/docs/:path', + text: '改进此页面的内容' + }, + + nav: [ + { text: '指南', link: '/zh/guide/' }, + { text: 'API 参考', link: '/zh/api/' }, + { text: '从 Vue 2 迁移', link: '/zh/migration/' }, + { + text: '更新日志', + link: 'https://github.com/vuejs/test-utils/releases' + } + ], + + sidebar: { + '/zh': [ + { + text: '安装', + link: '/zh/installation/' + }, + { + text: '基础知识', + items: [ + { + text: '开始', + link: '/zh/guide/' + }, + { + text: '快速上手', + link: '/zh/guide/essentials/a-crash-course' + }, + { + text: '条件渲染', + link: '/zh/guide/essentials/conditional-rendering' + }, + { + text: '测试事件触发', + link: '/zh/guide/essentials/event-handling' + }, + { + text: '测试表单', + link: '/zh/guide/essentials/forms' + }, + { + text: '传递数据到组件', + link: '/zh/guide/essentials/passing-data' + }, + { + text: '编写易于测试的组件', + link: '/zh/guide/essentials/easy-to-test' + } + ] + }, + { + text: '深入学习 Vue Test Utils', + items: [ + { + text: '插槽', + link: '/zh/guide/advanced/slots' + }, + { + text: '异步行为', + link: '/zh/guide/advanced/async-suspense' + }, + { + text: '发起 HTTP 请求', + link: '/zh/guide/advanced/http-requests' + }, + { + text: '过渡效果', + link: '/zh/guide/advanced/transitions' + }, + { + text: '组件实例', + link: '/zh/guide/advanced/component-instance' + }, + { + text: '复用与组合', + link: '/zh/guide/advanced/reusability-composition' + }, + { + text: '测试 v-model', + link: '/zh/guide/advanced/v-model' + }, + { + text: '测试 Vuex', + link: '/zh/guide/advanced/vuex' + }, + { + text: '测试 Vue Router', + link: '/zh/guide/advanced/vue-router' + }, + { + text: '测试 Teleport', + link: '/zh/guide/advanced/teleport' + }, + { + text: 'Stubs 和浅挂载', + link: '/zh/guide/advanced/stubs-shallow-mount' + }, + { + text: '测试服务端渲染', + link: '/zh/guide/advanced/ssr' + } + ] + }, + { + text: '扩展 Vue Test Utils', + items: [ + { + text: '插件', + link: '/zh/guide/extending-vtu/plugins' + }, + { + text: '社区与学习资源', + link: '/zh/guide/extending-vtu/community-learning' + } + ] + }, + { + text: '常见问题', + link: '/zh/guide/faq/' + }, + { + text: '从 Vue 2 迁移', + link: '/zh/migration/' + }, + { + text: 'API 参考', + link: '/zh/api/' + } + ] + } + } +} From fa42b2ed3d4941641d818330164f9becb185320c Mon Sep 17 00:00:00 2001 From: wuzhiqing Date: Wed, 20 Nov 2024 06:51:54 +0000 Subject: [PATCH 02/16] feat: add zh template (copied from English) --- docs/zh/README.md | 43 + docs/zh/api/index.md | 2046 +++++++++++++++++ docs/zh/guide/advanced/async-suspense.md | 151 ++ docs/zh/guide/advanced/component-instance.md | 84 + docs/zh/guide/advanced/http-requests.md | 174 ++ .../guide/advanced/reusability-composition.md | 218 ++ docs/zh/guide/advanced/slots.md | 191 ++ docs/zh/guide/advanced/ssr.md | 42 + docs/zh/guide/advanced/stubs-shallow-mount.md | 391 ++++ docs/zh/guide/advanced/teleport.md | 210 ++ docs/zh/guide/advanced/transitions.md | 68 + docs/zh/guide/advanced/v-model.md | 98 + docs/zh/guide/advanced/vue-router.md | 496 ++++ docs/zh/guide/advanced/vuex.md | 297 +++ docs/zh/guide/essentials/a-crash-course.md | 263 +++ .../guide/essentials/conditional-rendering.md | 149 ++ docs/zh/guide/essentials/easy-to-test.md | 125 + docs/zh/guide/essentials/event-handling.md | 157 ++ docs/zh/guide/essentials/forms.md | 410 ++++ docs/zh/guide/essentials/passing-data.md | 133 ++ .../guide/extending-vtu/community-learning.md | 8 + docs/zh/guide/extending-vtu/plugins.md | 183 ++ docs/zh/guide/faq/index.md | 34 + docs/zh/guide/index.md | 59 + docs/zh/index.md | 17 + docs/zh/installation/index.md | 20 + docs/zh/migration/index.md | 389 ++++ 27 files changed, 6456 insertions(+) create mode 100644 docs/zh/README.md create mode 100644 docs/zh/api/index.md create mode 100644 docs/zh/guide/advanced/async-suspense.md create mode 100644 docs/zh/guide/advanced/component-instance.md create mode 100644 docs/zh/guide/advanced/http-requests.md create mode 100644 docs/zh/guide/advanced/reusability-composition.md create mode 100644 docs/zh/guide/advanced/slots.md create mode 100644 docs/zh/guide/advanced/ssr.md create mode 100644 docs/zh/guide/advanced/stubs-shallow-mount.md create mode 100644 docs/zh/guide/advanced/teleport.md create mode 100644 docs/zh/guide/advanced/transitions.md create mode 100644 docs/zh/guide/advanced/v-model.md create mode 100644 docs/zh/guide/advanced/vue-router.md create mode 100644 docs/zh/guide/advanced/vuex.md create mode 100644 docs/zh/guide/essentials/a-crash-course.md create mode 100644 docs/zh/guide/essentials/conditional-rendering.md create mode 100644 docs/zh/guide/essentials/easy-to-test.md create mode 100644 docs/zh/guide/essentials/event-handling.md create mode 100644 docs/zh/guide/essentials/forms.md create mode 100644 docs/zh/guide/essentials/passing-data.md create mode 100644 docs/zh/guide/extending-vtu/community-learning.md create mode 100644 docs/zh/guide/extending-vtu/plugins.md create mode 100644 docs/zh/guide/faq/index.md create mode 100644 docs/zh/guide/index.md create mode 100644 docs/zh/index.md create mode 100644 docs/zh/installation/index.md create mode 100644 docs/zh/migration/index.md diff --git a/docs/zh/README.md b/docs/zh/README.md new file mode 100644 index 000000000..53ca3cabb --- /dev/null +++ b/docs/zh/README.md @@ -0,0 +1,43 @@ +# Vue Test Utils + +Component testing utils for Vue 3. + +## Languages + +[🇫🇷 French version of this README.md](https://github.com/vuejs/test-utils/tree/main/docs/fr/README.md) + +## Installation and Usage + +- yarn: `yarn add @vue/test-utils --dev` +- npm: `npm install @vue/test-utils --save-dev` + +Get started with the [documentation](https://test-utils.vuejs.org/). + +## Coming from Vue 2 + Test Utils v1? + +[Check the migration guide](https://test-utils.vuejs.org/migration/). It's still a work in progress. If you find a problem or something that doesn't work that previously did in Vue Test Utils v1, please open an issue. + +## Documentation + +See the [docs](https://test-utils.vuejs.org/). + +## Development + +Get started by running `pnpm install`. You can run the tests with `pnpm test`. That's it! + +## Contributing Docs + +All the documentation files can be found in `packages/docs`. It contains the English markdown files while translation(s) are stored in their corresponding `` sub-folder(s): + +- [`fr`](https://github.com/vuejs/test-utils/tree/main/packages/docs/fr): French translation. + +Besides that, the `.vitepress` sub-folder contains the config and theme, including the i18n information. + +- `pnpm docs:dev`: Start the docs dev server. +- `pnpm docs:build`: Build the docs. + +To add or maintain the translations, we follow the [Vue Ecosystem Translation Guidelines](https://github.com/vuejs-translations/guidelines/blob/main/README_ECOSYSTEM.md). + +- `pnpm docs:translation:status []`: Show the translation status for your language. If you don't specify a language, it will show the status for all languages. +- `pnpm docs:translation:compare `: Compare the docs with the latest checkpoint for your language. +- `pnpm docs:translation:update []`: Update the checkpoint for your language. The checkpoint will be set by the latest commit hash. However, you can also specify a commit hash manually. diff --git a/docs/zh/api/index.md b/docs/zh/api/index.md new file mode 100644 index 000000000..abf00506c --- /dev/null +++ b/docs/zh/api/index.md @@ -0,0 +1,2046 @@ +--- +sidebar: auto +--- + +# API Reference + +## mount + +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 { + attachTo?: Element | string + attrs?: Record + data?: () => {} extends Data ? any : Data extends object ? Partial : 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` 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: '
Hello world
' +} + +test('mounts a component', () => { + const wrapper = mount(Component, {}) + + expect(wrapper.html()).toContain('Hello world') +}) +``` + +Notice that `mount` accepts a second parameter to define the component's state configuration. + +**Example : mounting with component props and a Vue App plugin** + +```js +const wrapper = mount(Component, { + props: { + msg: 'world' + }, + global: { + plugins: [vuex] + } +}) +``` + +#### options.global + +Among component state, you can configure the aformentioned Vue 3 app by the [`MountingOptions.global` config property.](#global) This would be useful for providing mocked values which your components expect to have available. + +::: tip +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.](#config) +::: + +### attachTo + +Specify the node to mount the component on. This is not available when using `renderToString`. + +**Signature:** + +```ts +attachTo?: Element | string +``` + +**Details:** + +Can be a valid CSS selector, or an [`Element`](https://developer.mozilla.org/en-US/docs/Web/API/Element) connected to the document. + +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 + +``` + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +document.body.innerHTML = ` +
+

Non Vue app

+
+
+` + +test('mounts on a specific element', () => { + const wrapper = mount(Component, { + attachTo: document.getElementById('app') + }) + + expect(document.body.innerHTML).toBe(` +
+

Non Vue app

+

Vue Component

+
+`) +}) +``` + +### attrs + +Sets HTML attributes to component. + +**Signature:** + +```ts +attrs?: Record +``` + +**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' + }) +}) +``` + +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 + +Overrides a component's default `data`. Must be a function. + +**Signature:** + +```ts +data?: () => {} extends Data ? any : Data extends object ? Partial : any +``` + +**Details:** + +`Component.vue` + +```vue + + + +``` + +`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 + + + +``` + +`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:** + +Slots can be a string or any valid component definition either imported from a `.vue` file or provided inline + +`Component.vue`: + +```vue + +``` + +`Bar.vue`: + +```vue + +``` + +`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('

Named Slot

Default
Bar
') +}) +``` + +### global + +**Signature:** + +```ts +type GlobalMountOptions = { + plugins?: (Plugin | [Plugin, ...any[]])[] + config?: Partial> + mixins?: ComponentOptions[] + mocks?: Record + provide?: Record + components?: Record + directives?: Record + stubs?: Stubs = Record | Array + renderStubDefaultSlot?: boolean +} +``` + +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](#config-global). + +#### global.components + +Registers components globally to the mounted component. + +**Signature:** + +```ts +components?: Record +``` + +**Details:** + +`Component.vue`: + +```vue + + + +``` + +`GlobalComponent.vue`: + +```vue + +``` + +`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 + +Configures [Vue's application global configuration](https://v3.vuejs.org/api/application-config.html#application-config). + +**Signature:** + +```ts +config?: Partial> +``` + +#### global.directives + +Registers a [directive](https://v3.vuejs.org/api/directives.html#directives) globally to the mounted component. + +**Signature:** + +```ts +directives?: Record +``` + +**Details:** + +`Component.spec.js`: + +```js +import { mount } from '@vue/test-utils' + +import Directive from '@/directives/Directive' + +const Component = { + template: '
Foo
' +} + +test('global.directives', () => { + const wrapper = mount(Component, { + global: { + directives: { + Bar: Directive // Bar matches v-bar + } + } + }) +}) +``` + +#### global.mixins + +Registers a [mixin](https://v3.vuejs.org/guide/mixins.html) 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 + +Mocks a global instance property. Can be used for mocking out `this.$store`, `this.$router` etc. + +**Signature:** + +```ts +mocks?: Record +``` + +**Details:** + +::: warning +This is designed to mock variables injected by third party plugins, not Vue's native properties such as $root, $children, etc. +::: + +`Component.vue`: + +```vue + + + +``` + +`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 + +Provides data to be received in a `setup` function via `inject`. + +**Signature:** + +```ts +provide?: Record +``` + +**Details:** + +`Component.vue`: + +```vue + + + +``` + +`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()) //=>
Theme is dark
+}) +``` + +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 + +Renders the `default` slot content, even when using `shallow` or `shallowMount`. + +**Signature:** + +```ts +renderStubDefaultSlot?: boolean +``` + +**Details:** + +Defaults to **false**. + +`Component.vue` + +```vue + + + +``` + +`AnotherComponent.vue` + +```vue + +``` + +`Component.spec.js` + +```js +import { mount } from '@vue/test-utils' +import Component from './Component.vue' + +test('global.renderStubDefaultSlot', () => { + const wrapper = mount(ComponentWithSlots, { + slots: { + default: '
My slot content
' + }, + shallow: true, + global: { + renderStubDefaultSlot: true + } + }) + + expect(wrapper.html()).toBe( + '
My slot content
' + ) +}) +``` + +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 +``` + +**Details:** + +It stubs `Transition` and `TransitionGroup` by default. + +`Component.vue`: + +```vue + + + +``` + +`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('
') +}) + +test('global.stubs using object syntax', () => { + const wrapper = mount(Component, { + global: { + stubs: { Foo: true } + } + }) + + expect(wrapper.html()).toEqual('
') +}) + +test('global.stubs using a custom component', () => { + const CustomStub = { + name: 'CustomStub', + template: '

custom stub content

' + } + + const wrapper = mount(Component, { + global: { + stubs: { Foo: CustomStub } + } + }) + + expect(wrapper.html()).toEqual('

custom stub content

') +}) +``` + +### shallow + +Stubs out all child components from the component. + +**Signature:** + +```ts +shallow?: boolean +``` + +**Details:** + +Defaults to **false**. + +`Component.vue` + +```vue + + + +``` + +`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( + `` + ) +}) +``` + +::: tip +`shallowMount()` is an alias to mounting a component with `shallow: true`. +::: + +## Wrapper methods + +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. + +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 + +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 + + + +``` + +`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 + +``` + +`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(): Record +emitted(eventName: string): undefined | T[] +emitted(eventName?: string): undefined | T[] | Record +``` + +**Details:** + +The arguments are stored in an array, so you can verify which arguments were emitted along with each event. + +`Component.vue`: + +```vue + +``` + +`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:** + +You can use the same syntax `querySelector` implements. + +`Component.vue`: + +```vue + +``` + +`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 + +Finds an element and returns a `DOMWrapper` if one is found. + +**Signature:** + +```ts +find(selector: K): DOMWrapper +find(selector: K): DOMWrapper +find(selector: string): DOMWrapper +find(selector: string): DOMWrapper +find(selector: string | RefSelector): DOMWrapper; +``` + +**Details:** + +You can use the same syntax `querySelector` implements. `find` is basically an alias for `querySelector`. In addition you can search for element refs. + +It is similar to `get`, but `find` returns an ErrorWrapper if an element is not found while [`get`](#get) will throw an error. + +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`](#get). + + +`Component.vue`: + +```vue + +``` + +`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 + +Similar to `find`, but instead returns an array of `DOMWrapper`. + +**Signature:** + +```ts +findAll(selector: K): DOMWrapper[] +findAll(selector: K): DOMWrapper[] +findAll(selector: string): DOMWrapper[] +findAll(selector: string): DOMWrapper[] +``` + +**Details:** + +`Component.vue`: + +```vue + +``` + +`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 + +Finds a Vue Component instance and returns a `VueWrapper` if found. Returns `ErrorWrapper` otherwise. + +**Signature:** + +```ts +findComponent(selector: string): WrapperLike +findComponent(selector: T | Exclude): VueWrapper> +findComponent(selector: T | string): DOMWrapper +findComponent(selector: NameSelector | RefSelector): VueWrapper +findComponent(selector: T | FindComponentSelector): VueWrapper +findComponent(selector: FindComponentSelector): WrapperLike +``` + +**Details:** + +`findComponent` supports several syntaxes: + +| syntax | example | details | +| -------------- | ----------------------------- | ------------------------------------------------------------ | +| querySelector | `findComponent('.component')` | Matches standard query selector. | +| Component name | `findComponent({name: 'a'})` | matches PascalCase, snake-case, camelCase | +| Component ref | `findComponent({ref: 'ref'})` | Can be used only on direct ref children of mounted component | +| SFC | `findComponent(Component)` | Pass an imported component directly | + +`Foo.vue` + +```vue + + + +``` + +`Component.vue`: + +```vue + + + +``` + +`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) +}) +``` + +:::warning +If `ref` in component points to HTML element, `findComponent` will return empty wrapper. This is intended behaviour. +::: + +:::warning Usage with CSS selectors +Using `findComponent` with CSS selector might have confusing behavior + +Consider this example: + +```js +const ChildComponent = { + name: 'Child', + template: '
' +} +const RootComponent = { + name: 'Root', + components: { ChildComponent }, + template: '' +} +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 +``` + +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 +::: + +:::info WrapperLike type when using CSS selector +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('.foo') // returns VueWrapper +wrapper.findComponent('.foo') // returns VueWrapper +``` +::: + +### findAllComponents + +**Signature:** + +```ts +findAllComponents(selector: string): WrapperLike[] +findAllComponents(selector: T | Exclude): VueWrapper>[] +findAllComponents(selector: string): DOMWrapper[] +findAllComponents(selector: T): DOMWrapper[] +findAllComponents(selector: NameSelector): VueWrapper[] +findAllComponents(selector: T | FindAllComponentsSelector): VueWrapper[] +findAllComponents(selector: FindAllComponentsSelector): WrapperLike[] +``` + +**Details:** + +Similar to `findComponent` but finds all Vue Component instances that match the query. Returns an array of `VueWrapper`. + +:::warning +`ref` syntax is not supported in `findAllComponents`. All other query syntaxes are valid. +::: + +`Component.vue`: + +```vue + +``` + +`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"]') +}) +``` + +:::warning Usage with CSS selectors +`findAllComponents` has same behavior when used with CSS selector as [findComponent](#findcomponent) +::: + +### get + +Gets an element and returns a `DOMWrapper` if found. Otherwise it throws an error. + +**Signature:** + +```ts +get(selector: K): Omit, 'exists'> +get(selector: K): Omit, 'exists'> +get(selector: string): Omit, 'exists'> +get(selector: string): Omit, 'exists'> +``` + +**Details:** + +It is similar to `find`, but `get` throws an error if an element is not found while [`find`](#find) will return an ErrorWrapper. + +As a rule of thumb, always use `get` except when you are asserting something doesn't exist. In that case use [`find`](#find). + +`Component.vue`: + +```vue + +``` + +`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 + +Gets a Vue Component instance and returns a `VueWrapper` if found. Otherwise it throws an error. + +**Signature:** + +```ts +getComponent(selector: new () => T): Omit, 'exists'> +getComponent(selector: { name: string } | { ref: string } | string): Omit, 'exists'> +getComponent(selector: any): Omit, 'exists'> +``` + +**Details:** + +It is similar to `findComponent`, but `getComponent` throws an error if a Vue Component instance is not found while [`findComponent`](#findComponent) will return an ErrorWrapper. + +**Supported syntax:** + +| syntax | example | details | +| -------------- | ---------------------------- | ------------------------------------------------------------ | +| querySelector | `getComponent('.component')` | Matches standard query selector. | +| Component name | `getComponent({name: 'a'})` | matches PascalCase, snake-case, camelCase | +| Component ref | `getComponent({ref: 'ref'})` | Can be used only on direct ref children of mounted component | +| SFC | `getComponent(Component)` | Pass an imported component directly | + +`Foo.vue` + +```vue + + + +``` + +`Component.vue`: + +```vue + + + +``` + +`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 + +Returns the HTML of an element. + +By default the output is formatted with [`js-beautify`](https://github.com/beautify-web/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 + +``` + +`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( + '
\n' + + '

Hello world

\n' + + '
' + ) + + expect(wrapper.html({ raw: true })).toBe('

Hello world

') +}) +``` + +### isVisible + +Verify whether an element is visible or not. + +**Signature:** + +```ts +isVisible(): boolean +``` + +**Details:** + +::: warning +`isVisible()` only works correctly if the wrapper is attached to the DOM using [`attachTo`](#attachTo) +::: + +```js +const Component = { + template: `
` +} + +test('isVisible', () => { + const wrapper = mount(Component, { + attachTo: document.body + }); + + expect(wrapper.find('span').isVisible()).toBe(false); +}) +``` + +### 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 + + + +``` + +`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' + }) +}) +``` + +:::tip +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): Promise +``` + +**Details:** + +`setData` does not allow setting new properties that are not defined in the component. + +::: warning +Also, notice that `setData` does not modify composition API `setup()` data. +::: + +`Component.vue`: + +```vue + + + +``` + +`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') +}) +``` + +::: warning +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): Promise +``` + +**Details:** + +`Component.vue`: + +```vue + + + +``` + +`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') +}) +``` + +::: warning +You should use `await` when you call `setProps` to ensure that Vue updates the DOM before you make an assertion. +::: + +### setValue + +Sets a value on DOM element. Including: + +- `` + - `type="checkbox"` and `type="radio"` are detected and will have `element.checked` set. +- `