diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3f8ea5fef..13e4541c9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
- node-version: [10.x, 12.x, 14.x, 15.x]
+ node-version: [12.x, 14.x, 15.x]
steps:
- uses: actions/checkout@v2
diff --git a/README.md b/README.md
index 24bafc4fe..4328ea69f 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,8 @@ The next iteration of Vue Test Utils. It targets Vue 3.
- yarn: `yarn add @vue/test-utils@next --dev`
- npm: `npm install @vue/test-utils@next --save-dev`
+Get started with the [documentation](https://vue-test-utils.vuejs.org/v2/).
+
## Coming from Vue 2 + Vue Test Utils?
We are working on [some documentation to help people migrate](https://vue-test-utils.vuejs.org/v2/guide/migration.html).
@@ -19,9 +21,9 @@ There is [`vue-jest`](https://github.com/vuejs/vue-jest) for loading `.vue` file
If you don't want to configure things, you can download a repository with Vue 3, `@vue/test-utils@next`, `vue-jest@next` and TypeScript configured [here](https://github.com/lmiller1990/vtu-next-demo).
-## Docs
+## What works?
-Docs are located in [this repo](https://github.com/vuejs/vue-test-utils-next-docs). Read them [here](https://vue-test-utils.vuejs.org/v2/). They are in a separate repository because running Vuepress alongside a repo with Vue 3 causes conflicts - Vuepress expects to be running against Vue 2. This seems like the most simple solution for now.
+See the [docs](https://vuejs.github.io/vue-test-utils-next-docs/guide/introduction.html).
## Development
@@ -29,17 +31,13 @@ It's a pretty small codebase at the moment. Get started by running `yarn install
There is still some work left to do. See issues for some basic TODOs, or the table at the bottom of this page.
-## What works?
-
-See the [docs](https://vuejs.github.io/vue-test-utils-next-docs/guide/introduction.html).
-
## Contributing
This is still quite alpha, but we plan on moving to RC sooner than later. If you want to add a feature, have a hack or ping someone in Discord to chat, or check out the issues and project board.
There's also some [work left to do in docs](https://github.com/vuejs/vue-test-utils-next-docs/issues).
-## Comparsion with Vue Test Utils beta (targeting Vue 2)
+## Comparison with Vue Test Utils beta (targeting Vue 2)
This is table for those coming from VTU 1, comparing the two APIs. Some things are still a work in progress.
@@ -49,54 +47,53 @@ This is table for those coming from VTU 1, comparing the two APIs. Some things a
### Mounting Options
-| option | status | notes |
-|---------|-------|------|
-data | ✅
-slots | ✅ | has not been tested vigorously. Please try it out.
-mocks | ✅ | nested in [`global`](https://vuejs.github.io/vue-test-utils-next-docs/api/#global)
-propsData | ✅ | now called `props`
-provide | ✅ | nested in [`global`](https://vuejs.github.io/vue-test-utils-next-docs/api/#global)
-mixins | ✅ | (new!) nested in [`global`](https://vuejs.github.io/vue-test-utils-next-docs/api/#global)
-plugins | ✅ | (new!) nested in [`global`](https://vuejs.github.io/vue-test-utils-next-docs/api/#global)
-component | ✅ | (new!) nested in [`global`](https://vuejs.github.io/vue-test-utils-next-docs/api/#global)
-directives | ✅ | (new!) nested in [`global`](https://vuejs.github.io/vue-test-utils-next-docs/api/#global)
-stubs | ✅
-attachToDocument |✅| renamed `attachTo`. See [here](https://github.com/vuejs/vue-test-utils/pull/1492)
-attrs | ✅
-scopedSlots | ⚰️ | scopedSlots are merged with slots in Vue 3
-context | ⚰️ | different from Vue 2, does not make sense anymore.
-localVue | ⚰️ | may not make sense anymore since we do not mutate the global Vue instance in Vue 3.
-listeners | ⚰️ | no longer exists in Vue 3
-parentComponent | ⚰️ |
-
+| option | status | notes |
+| ---------------- | ------ | ----------------------------------------------------------------------------------------- |
+| data | ✅ |
+| slots | ✅ | has not been tested vigorously. Please try it out. |
+| mocks | ✅ | nested in [`global`](https://vuejs.github.io/vue-test-utils-next-docs/api/#global) |
+| propsData | ✅ | now called `props` |
+| provide | ✅ | nested in [`global`](https://vuejs.github.io/vue-test-utils-next-docs/api/#global) |
+| mixins | ✅ | (new!) nested in [`global`](https://vuejs.github.io/vue-test-utils-next-docs/api/#global) |
+| plugins | ✅ | (new!) nested in [`global`](https://vuejs.github.io/vue-test-utils-next-docs/api/#global) |
+| component | ✅ | (new!) nested in [`global`](https://vuejs.github.io/vue-test-utils-next-docs/api/#global) |
+| directives | ✅ | (new!) nested in [`global`](https://vuejs.github.io/vue-test-utils-next-docs/api/#global) |
+| stubs | ✅ |
+| attachToDocument | ✅ | renamed `attachTo`. See [here](https://github.com/vuejs/vue-test-utils/pull/1492) |
+| attrs | ✅ |
+| scopedSlots | ⚰️ | scopedSlots are merged with slots in Vue 3 |
+| context | ⚰️ | different from Vue 2, does not make sense anymore. |
+| localVue | ⚰️ | may not make sense anymore since we do not mutate the global Vue instance in Vue 3. |
+| listeners | ⚰️ | no longer exists in Vue 3 |
+| parentComponent | ⚰️ |
### Wrapper API (mount)
-| method | status | notes |
-|---------|-------|------|
-attributes | ✅
-classes | ✅
-exists | ✅
-find | ✅ | only `querySelector` syntax is supported. `find(Comp)` under discussion [here](https://github.com/vuejs/vue-test-utils/issues/1498)
-emitted | ✅
-findAll | ✅ | see above. `.vm` is different to Vue 2. We are exploring options.
-get | ✅
-html | ✅
-setValue | ✅ | works for select, checkbox, radio button, input, textarea. Returns `nextTick`.
-text | ✅ |
-trigger | ✅ | returns `nextTick`. You can do `await wrapper.find('button').trigger('click')`
-setProps | ✅ |
-props | ✅
-setData | ✅ |
-destroy | ✅ | renamed to `unmount` to match Vue 3 lifecycle hook name.
-props | ✅
-isVisible | ✅
-contains | ⚰️| use `find`
-emittedByOrder | ⚰️ | use `emitted`
-setSelected | ⚰️ | now part of `setValue`
-setChecked | ⚰️| now part of `setValue`
-is | ⚰️
-isEmpty | ⚰️ | use matchers such as [this](https://github.com/testing-library/jest-dom#tobeempty)
-isVueInstance | ⚰️
-name | ⚰️ |
-setMethods | ⚰️ |
+| method | status | notes |
+| -------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------- |
+| attributes | ✅ |
+| classes | ✅ |
+| exists | ✅ |
+| find | ✅ | only `querySelector` syntax is supported. `find(Comp)` under discussion [here](https://github.com/vuejs/vue-test-utils/issues/1498) |
+| emitted | ✅ |
+| findAll | ✅ | see above. `.vm` is different to Vue 2. We are exploring options. |
+| get | ✅ |
+| html | ✅ |
+| setValue | ✅ | works for select, checkbox, radio button, input, textarea. Returns `nextTick`. |
+| text | ✅ |
+| trigger | ✅ | returns `nextTick`. You can do `await wrapper.find('button').trigger('click')` |
+| setProps | ✅ |
+| props | ✅ |
+| setData | ✅ |
+| destroy | ✅ | renamed to `unmount` to match Vue 3 lifecycle hook name. |
+| props | ✅ |
+| isVisible | ✅ |
+| contains | ⚰️ | use `find` |
+| emittedByOrder | ⚰️ | use `emitted` |
+| setSelected | ⚰️ | now part of `setValue` |
+| setChecked | ⚰️ | now part of `setValue` |
+| is | ⚰️ |
+| isEmpty | ⚰️ | use matchers such as [this](https://github.com/testing-library/jest-dom#tobeempty) |
+| isVueInstance | ⚰️ |
+| name | ⚰️ |
+| setMethods | ⚰️ |
diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js
new file mode 100644
index 000000000..1dbc98df1
--- /dev/null
+++ b/docs/.vitepress/config.js
@@ -0,0 +1,116 @@
+/** @typedef {import('vitepress').UserConfig} UserConfig */
+
+/** @type {UserConfig} */
+const config = {
+ // base: '/v2/',
+ title: 'Vue Test Utils for Vue 3',
+ description: 'The documentation for the official Vue Test Utils',
+ locales: {
+ '/': {
+ lang: 'en-US',
+ title: 'Vue Test Utils (2.0.0-beta.14)'
+ }
+ },
+ head: [['link', { rel: 'icon', href: `/logo.png` }]],
+ themeConfig: {
+ repo: 'vuejs/vue-test-utils-next',
+ docsRepo: 'vuejs/vue-test-utils-next',
+ docsDir: 'docs',
+ docsBranch: 'master',
+ editLinks: true,
+ nav: [
+ { text: 'Guide', link: '/introduction/' },
+ { text: 'API Reference', link: '/api/' },
+ { text: 'Migrating from Vue 2', link: '/migration/' },
+ {
+ text: 'Changelog',
+ link: 'https://github.com/vuejs/vue-test-utils-next/releases'
+ }
+ ],
+ sidebar: [
+ {
+ text: 'Introduction',
+ link: '/introduction/'
+ },
+ {
+ text: 'Installation',
+ link: '/installation/'
+ },
+ {
+ text: 'Essentials',
+ collapsable: false,
+ children: [
+ { text: 'A Crash Course', link: '/guide/essentials/a-crash-course' },
+ {
+ text: 'Conditional Rendering',
+ link: '/guide/essentials/conditional-rendering'
+ },
+ {
+ text: 'Testing Emitted Events',
+ link: '/guide/essentials/event-handling'
+ },
+ { text: 'Testing Forms', link: '/guide/essentials/forms' },
+ {
+ text: 'Passing Data to Components',
+ link: '/guide/essentials/passing-data'
+ }
+ ]
+ },
+ {
+ text: 'Vue Test Utils in depth',
+ collapsable: false,
+ children: [
+ { text: 'Slots', link: '/guide/advanced/slots' },
+ {
+ text: 'Asynchronous Behavior',
+ link: '/guide/advanced/async-suspense'
+ },
+ {
+ text: 'Making HTTP Requests',
+ link: '/guide/advanced/http-requests'
+ },
+ { text: 'Transitions', link: '/guide/advanced/transitions' },
+ {
+ text: 'Component Instance',
+ link: '/guide/advanced/component-instance'
+ },
+ {
+ text: 'Reusability and Composition',
+ link: '/guide/advanced/reusability-composition'
+ },
+ { text: 'Testing Vuex', link: '/guide/advanced/vuex' },
+ { text: 'Testing Vue Router', link: '/guide/advanced/vue-router' },
+ {
+ text: 'Third-party integration',
+ link: '/guide/advanced/third-party'
+ },
+ {
+ text: 'Stubs and Shallow Mount',
+ link: '/guide/advanced/stubs-shallow-mount'
+ }
+ ]
+ },
+ {
+ text: 'Extending Vue Test Utils',
+ collapsable: false,
+ children: [
+ { text: 'Plugins', link: '/guide/extending-vtu/plugins' },
+ {
+ text: 'Community and Learning',
+ link: '/guide/extending-vtu/community-learning'
+ }
+ ]
+ },
+ {
+ text: 'Migrating from Vue 2',
+ link: '/migration/'
+ },
+ {
+ text: 'API Reference',
+ link: '/api/'
+ }
+ ]
+ }
+}
+
+module.exports = config
diff --git a/docs/API.md b/docs/API.md
deleted file mode 100644
index 38fcf18a9..000000000
--- a/docs/API.md
+++ /dev/null
@@ -1,579 +0,0 @@
-# API Reference
-
-## Mounting Options
-
-When using `mount`, you can predefine the component's state using mounting options.
-
-### `props`
-
-```vue
-
- Count: {{ count }}
-
-
-
-```
-
-```js
-test('props', () => {
- const wrapper = mount(Component, {
- props: {
- count: 5
- }
- })
-
- console.log(wrapper.html()) //=> 'Count: 5 '
-})
-```
-
-### `data`
-
-Overrides a component's default `data`. Must be a function:
-
-```vue
-
- Foo is {{ foo }}
-
-
-
-```
-
-```js
-test('overrides data', () => {
- const wrapper = mount(Component, {
- data() {
- return {
- foo: 'bar'
- }
- }
- })
-
- console.log(wrapper.html()) //=> '
Foo is bar
'
-})
-```
-
-### `slots`
-
-```vue
-
-
-
-
-```
-
-```js
-test('slots - default and named', () => {
- const wrapper = mount(Component, {
- slots: {
- default: 'Default',
- foo: h('h1', {}, 'Named Slot')
- }
- })
-
- console.log(wrapper.html()) //=> 'Named Slot Default'
-})
-```
-
-## `provides`
-
-Provides data to be received in a `setup` function via `inject`.
-
-```vue
-
- Theme is {{ theme }}
-
-
-
-```
-
-```js
-test('injects dark theme via provide mounting option', () => {
- const wrapper = mount(Component, {
- provides: {
- 'Theme': 'dark'
- }
- })
-
- console.log(wrapper.html()) //=> Theme is dark
-})
-```
-
-Note: If you are using a ES6 `Symbol` for your provide key, you can use it as a dynamic key:
-
-```js
-const ThemeSymbol = Symbol()
-
-mount(Component, {
- provides: {
- [ThemeSymbol]: 'value'
- }
-})
-```
-### Global
-You can provide properties to the App instance using the properties under the `global` mount property
-
-### `global.mixins`
-
-Applies mixins via `app.mixin(...)`.
-
-```vue
-
-
-
-
-
-```
-
-```js
-test('adds a lifecycle mixin', () => {
- const mixin = {
- created() {
- console.log('Component was created!')
- }
- }
-
- const wrapper = mount(Component, {
- global: {
- mixins: [mixin]
- }
- })
-
- // 'Component was created!' will be logged
-})
-```
-
-### `global.plugins`
-
-Installs plugins on the component.
-
-```vue
-
-
-
-
-
-```
-
-```js
-test('installs plugins via `plugins`', () => {
- const installed = jest.fn()
- class Plugin {
- static install() {
- installed()
- }
- }
-
- const installedWithOptions = jest.fn()
- class PluginWithOptions {
- static install(_app: App, ...args) {
- installedWithOptions(...args)
- }
- }
-
- const Component = {
- render() {
- return h('div')
- }
- }
- mount(Component, {
- global: {
- plugins: [Plugin, [PluginWithOptions, 'argument 1', 'another argument']]
- }
- })
-
- expect(installed).toHaveBeenCalled()
- expect(installedWithOptions).toHaveBeenCalledWith(
- 'argument 1',
- 'another argument'
- )
-})
-```
-
-
-### `global.components`
-
-Registers components globally to all components
-
-```js
-test('installs a component globally', () => {
- import GlobalComponent from '@/components/GlobalComponent'
-
- const Component = {
- template: '
'
- }
- const wrapper = mount(Component, {
- global: {
- components: {
- GlobalComponent
- }
- }
- })
-
- expect(wrapper.find('.global-component').exists()).toBe(true)
-})
-```
-
-### `global.directives`
-
-Registers a directive globally to all components
-
-```js
-test('installs a directive globally', () => {
- import Directive from '@/directives/Directive'
-
- const Component = {
- template: 'Foo
'
- }
- const wrapper = mount(Component, {
- global: {
- directives: {
- Bar: Directive
- }
- }
- })
-
- expect(wrapper.classes()).toContain('added-by-bar')
-})
-```
-
-## Wrapper
-
-When you use `mount`, a `VueWrapper` is returned with a number of useful methods for testing. Methods like `find` return a `DOMWrapper`. Both implement the same API.
-
-
-### `html`
-
-Returns the HTML (via `outerHTML`) of an element. Useful for debugging.
-
-```vue
-
-
-
-```
-
-```js
-test('html', () => {
- const wrapper = mount(Component)
-
- console.log(wrapper.html()) //=>
-})
-```
-
-### `text`
-
-Find the text (via `textContent`) of an element.
-
-```vue
-
-
-
-```
-
-```js
-test('text', () => {
- const wrapper = mount(Component)
-
- expect(wrapper.find('p').text()).toBe('Hello world')
-})
-```
-
-### `find`
-
-Finds an element and returns a `DOMWrapper` if one is found. You can use the same syntax `querySelector` implements - `find` is basically an alias for `querySelector`.
-
-```vue
-
-
- Span
- Span
-
-
-```
-
-```js
-test('find', () => {
- const wrapper = mount(Component)
-
- wrapper.find('span') //=> found; returns DOMWrapper
- wrapper.find('[data-test="span"]') //=> found; returns DOMWrapper
- wrapper.find('p') //=> nothing found; returns ErrorWrapper
-})
-```
-
-### `findAll`
-
-Similar to `find`, but instead returns an array of `DOMWrapper`.
-
-```vue
-
-
-
- {{ number }}
-
-
-
-```
-
-```js
-test('findAll', () => {
- const wrapper = mount(Component)
-
- wrapper.findAll('[data-test="number"]') //=> found; returns array of DOMWrapper
-})
-```
-
-### `findComponent`
-
-Finds a Vue Component instance and returns a `VueWrapper` if one is found, otherwise returns `ErrorWrapper`.
-
-**Supported syntax:**
-
-* **querySelector** - `findComponent('.component')` - Matches standard query selector.
-* **Name** - `findComponent({ name: 'myComponent' })` - matches PascalCase, snake-case, camelCase
-* **ref** - `findComponent({ ref: 'dropdown' })` - Can be used only on direct ref children of mounted component
-* **SFC** - `findComponent(ImportedComponent)` - Pass an imported component directly.
-
-```vue
-
-
- Foo
-
-
-
-```
-
-```vue
-
-
- Span
-
-
-
-```
-
-```js
-test('findComponent', () => {
- const wrapper = mount(Component)
-
- wrapper.findComponent('.foo') //=> found; returns VueWrapper
- wrapper.findComponent('[data-test="foo"]') //=> found; returns VueWrapper
- wrapper.findComponent({ name: 'Foo' }) //=> found; returns VueWrapper
- wrapper.findComponent({ name: 'foo' }) //=> found; returns VueWrapper
- wrapper.findComponent({ ref: 'foo' }) //=> found; returns VueWrapper
- wrapper.findComponent(Foo) //=> found; returns VueWrapper
-})
-```
-
-### `findAllComponents`
-
-Similar to `findComponent` but finds all Vue Component instances that match the query and returns an array of `VueWrapper`.
-
-**Supported syntax:**
-
- * **querySelector** - `findAllComponents('.component')`
- * **Name** - `findAllComponents({ name: 'myComponent' })`
- * **SFC** - `findAllComponents(ImportedComponent)`
-
-**Note** - `Ref` is not supported here.
-
-
-```vue
-
-
-
- {{ number }}
-
-
-
-```
-
-```js
-test('findAllComponents', () => {
- const wrapper = mount(Component)
-
- wrapper.findAllComponents('[data-test="number"]') //=> found; returns array of VueWrapper
-})
-```
-
-### `trigger`
-
-Simulates an event, for example `click`, `submit` or `keyup`. Since events often cause a re-render, `trigger` returs `Vue.nextTick`. If you expect the event to trigger a re-render, you should use `await` when you call `trigger` to ensure that Vue updates the DOM before you make an assertion.
-
-```vue
-
-
- Count: {{ count }}
- Greet
-
-
-
-
-```
-
-```js
-test('trigger', async () => {
- const wrapper = mount(Component)
-
- await wrapper.find('button').trigger('click')
-
- expect(wrapper.find('span').text()).toBe('Count: 1')
-})
-```
-
-### `classes`
-
-Returns an array of classes on an element (via `classList`).
-
-```vue
-
-
-
-
-
-```
-
-```js
-test('classes', () => {
- const wrapper = mount(Component)
-
- expect(wrapper.find('.my-span').classes()).toContain('my-span')
-})
-```
-
-### `exists`
-
-Verify whether or not an element found via `find` exists or not.
-
-```vue
-
-
-
-
-
-```
-
-```js
-test('exists', () => {
- const wrapper = mount(Component)
-
- expect(wrapper.find('span').exists()).toBe(true)
-})
-```
-
-### `emitted`
-
-Returns an object mapping events emitted from the `wrapper`. The arguments are stored in an array, so you can verify which arguments were emitted each time the event is emitted.
-
-```vue
-
-
-
-
-
+```
+
+`Component.spec.js`:
+
+```js
+test('mounts on a specific element', () => {
+ // in a JSDOM environment, such as Jest
+ document.body.innerHTML = `
+
+ `
+ const wrapper = mount(Component, {
+ attachTo: document.getElementById('app')
+ })
+
+ console.log(document.body.innerHTML)
+ /*
+ *
+ *
Non Vue app
+ *
Vue Component
+ *
+ */
+})
+```
+
+### `attrs`
+
+Assigns attributes to component.
+
+```js
+test('assigns extra attributes on components', () => {
+ const wrapper = mount(Component, {
+ attrs: {
+ id: 'hello',
+ disabled: true
+ }
+ })
+
+ expect(wrapper.attributes()).toEqual({
+ disabled: 'true',
+ id: 'hello'
+ })
+})
+```
+
+Notice that setting a prop will always trump an attribute:
+
+```js
+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.
+
+`Component.vue`
+
+```vue
+
+ Foo is {{ foo }}
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+test('overrides data', () => {
+ const wrapper = mount(Component, {
+ data() {
+ return {
+ foo: 'bar'
+ }
+ }
+ })
+
+ expect(wrapper.html()).toContain('Foo is bar')
+})
+```
+
+### `props`
+
+Used to set props on a component when mounted.
+
+`Component.vue`:
+
+```vue
+
+ Count: {{ count }}
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+test('props', () => {
+ const wrapper = mount(Component, {
+ props: {
+ count: 5
+ }
+ })
+
+ expect(wrapper.html()).toContain('Count: 5')
+})
+```
+
+### `slots`
+
+Provide values for slots on a component. Slots can be a component imported from a `.vue` file or a render function. Currently providing an object with a `template` key is not supported. This may be supported in the future.
+
+`Component.vue`:
+
+```vue
+
+
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+import Bar from './Bar.vue'
+
+test('renders slots content', () => {
+ const wrapper = mount(Component, {
+ slots: {
+ default: 'Default',
+ foo: h('h1', {}, 'Named Slot'),
+ bar: Bar
+ }
+ })
+
+ console.log(wrapper.html()) //=> 'Named Slot DefaultBar
'
+})
+```
+
+### `global.components`
+
+Registers components globally to all components
+
+`Component.spec.js`:
+
+```js
+import GlobalComponent from '@/components/GlobalComponent'
+
+test('installs a component globally', () => {
+ const Component = {
+ template: '
'
+ }
+
+ const wrapper = mount(Component, {
+ global: {
+ components: {
+ GlobalComponent
+ }
+ }
+ })
+
+ expect(wrapper.find('.global-component').exists()).toBe(true)
+})
+```
+
+### `global.directives`
+
+Registers a directive globally to all components
+
+`Component.spec.js`:
+
+```js
+import Directive from '@/directives/Directive'
+
+test('installs a directive globally', () => {
+ const Component = {
+ template: 'Foo
'
+ }
+
+ const wrapper = mount(Component, {
+ global: {
+ directives: {
+ Bar: Directive
+ }
+ }
+ })
+
+ expect(wrapper.classes()).toContain('added-by-bar')
+})
+```
+
+### `global.mixins`
+
+Applies mixins via `app.mixin(...)`.
+
+`Component.spec.js`:
+
+```js
+test('adds a lifecycle mixin', () => {
+ const mixin = {
+ created() {
+ console.log('Component was created!')
+ }
+ }
+
+ const Component = { template: '
' }
+
+ const wrapper = mount(Component, {
+ global: {
+ mixins: [mixin]
+ }
+ })
+
+ // 'Component was created!' will be logged
+})
+```
+
+### `global.mocks`
+
+Mocks a global instance property. Can be used for mocking out `this.$store`, `this.$router` etc.
+
+::: 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
+
+ {{ count }}
+
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+test('mocks a vuex store', async () => {
+ const $store = {
+ state: { count: 1 },
+ dispatch: jest.fn()
+ }
+
+ const wrapper = mount(Component, {
+ global: {
+ mocks: {
+ $store
+ }
+ }
+ })
+
+ expect(wrapper.html()).toContain('count: 1')
+
+ await wrapper.find('button').trigger('click')
+
+ expect($store.dispatch).toHaveBeenCalledWith('inc')
+})
+```
+
+### `global.plugins`
+
+Installs plugins on the component.
+
+`Component.vue`:
+
+```vue
+
+
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+test('installs a plugin via `plugins`', () => {
+ const installed = jest.fn()
+ class Plugin {
+ static install() {
+ installed()
+ }
+ }
+ const options = { option1: true }
+ const testString = 'hello'
+ mount(Component, {
+ global: {
+ plugins: [Plugin]
+ }
+ })
+
+ expect(installed).toHaveBeenCalled()
+})
+```
+
+To use plugin with options, an array of options can be passed.
+
+`Component.spec.js`:
+
+```js
+test('installs plugins with and without options', () => {
+ const installed = jest.fn()
+ class Plugin {
+ static install() {
+ installed()
+ }
+ }
+
+ const installedWithOptions = jest.fn()
+ class PluginWithOptions {
+ static install(_app: App, ...args) {
+ installedWithOptions(...args)
+ }
+ }
+
+ const Component = {
+ render() {
+ return h('div')
+ }
+ }
+ mount(Component, {
+ global: {
+ plugins: [Plugin, [PluginWithOptions, 'argument 1', 'another argument']]
+ }
+ })
+
+ expect(installed).toHaveBeenCalled()
+ expect(installedWithOptions).toHaveBeenCalledWith(
+ 'argument 1',
+ 'another argument'
+ )
+})
+```
+
+### `global.provide`
+
+Provides data to be received in a `setup` function via `inject`.
+
+`Component.vue`:
+
+```vue
+
+ Theme is {{ theme }}
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+test('injects dark theme via provide mounting option', () => {
+ const wrapper = mount(Component, {
+ global: {
+ provide: {
+ Theme: 'dark'
+ }
+ }
+ })
+
+ console.log(wrapper.html()) //=> Theme is dark
+})
+```
+
+Note: If you are using a ES6 `Symbol` for your provide key, you can use it as a dynamic key:
+
+`Component.spec.js`:
+
+```js
+const ThemeSymbol = Symbol()
+
+mount(Component, {
+ global: {
+ provide: {
+ [ThemeSymbol]: 'value'
+ }
+ }
+})
+```
+
+### `global.stubs`
+
+Stubs a component for all Vue Instances.
+
+`Component.vue`:
+
+```vue
+
+
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+test('stubs a component using an array', () => {
+ const wrapper = mount(Component, {
+ global: {
+ stubs: ['Foo']
+ }
+ })
+
+ expect(wrapper.html()).toEqual('
')
+})
+
+test('stubs a component using an Object boolean syntax', () => {
+ const wrapper = mount(Component, {
+ global: {
+ stubs: { Foo: true }
+ }
+ })
+
+ expect(wrapper.html()).toEqual('
')
+})
+
+test('stubs a component using a custom component', () => {
+ const FooMock = {
+ name: 'Foo',
+ template: 'FakeFoo'
+ }
+ const wrapper = mount(Component, {
+ global: {
+ stubs: { Foo: FooMock }
+ }
+ })
+
+ expect(wrapper.html()).toEqual('FakeFoo
')
+})
+```
+
+### `global.config`
+
+Configures [Vue's application global configuration](https://v3.vuejs.org/api/application-config.html#application-config).
+
+### `global.renderStubDefaultSlot`
+
+Renders the `default` slot content, even when using `shallow` or `shallowMount`.
+
+Due to technical limitations, this behavior cannot be extended to slots other than the default one.
+
+```js
+import { config, mount } from '@vue/test-utils'
+
+beforeAll(() => {
+ config.renderStubDefaultSlot = true
+})
+
+afterAll(() => {
+ config.renderStubDefaultSlot = false
+})
+
+test('shallow with stubs', () => {
+ const Component = {
+ template: `
`
+ }
+
+ const wrapper = mount(Component, {
+ shallow: true
+ })
+
+ expect(wrapper.html()).toContain('Content from the default slot')
+})
+```
+
+::: tip
+This behavior is global, not on a mount by mount basis. Remember to enable/disable it before and after each test.
+:::
+
+### `shallow`
+
+Stubs out out all child components from the components under testing.
+
+```js
+test('stubs all components automatically using { shallow: true }', () => {
+ const Component = {
+ template: `
+
+
+ `,
+ components: {
+ CustomComponent,
+ AnotherComponent
+ }
+ }
+
+ 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. Methods like `find` return a `DOMWrapper`, which is a thin wrapper around the DOM nodes in your component and it's children. Both implement a similar same API.
+
+### `attributes`
+
+Returns attributes on a DOM node (via `element.attributes`).
+
+`Component.vue`:
+
+```vue
+
+
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+test('attributes', () => {
+ const wrapper = mount(Component)
+
+ expect(wrapper.attributes('id')).toBe('foo')
+ expect(wrapper.attributes('class')).toBe('bar')
+})
+```
+
+### `classes`
+
+Returns an array of classes on an element (via `classList`).
+
+`Component.vue`:
+
+```vue
+
+
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+test('classes', () => {
+ const wrapper = mount(Component)
+
+ expect(wrapper.find('.my-span').classes()).toContain('my-span')
+})
+```
+
+### `emitted`
+
+A function that returns an object mapping events emitted from the `wrapper`. 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
+test('emitted', () => {
+ const wrapper = mount(Component)
+
+ console.log(wrapper.emitted())
+ // {
+ // greet: [ ['hello'], ['goodbye'] ]
+ // }
+
+ expect(wrapper.emitted()).toHaveProperty('greet')
+ expect(wrapper.emitted().greet[0]).toEqual(['hello'])
+ expect(wrapper.emitted().greet[1]).toEqual(['goodbye'])
+})
+```
+
+### `exists`
+
+Verify whether or not an element found via `find` exists or not.
+
+`Component.vue`:
+
+```vue
+
+
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+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. You can use the same syntax `querySelector` implements - `find` is basically an alias for `querySelector`.
+
+`Component.vue`:
+
+```vue
+
+
+ Span
+ Span
+
+
+```
+
+`Component.spec.js`:
+
+```js
+test('find', () => {
+ const wrapper = mount(Component)
+
+ wrapper.find('span') //=> found; returns DOMWrapper
+ wrapper.find('[data-test="span"]') //=> found; returns DOMWrapper
+ wrapper.find('p') //=> nothing found; returns ErrorWrapper
+})
+```
+
+### `findAll`
+
+Similar to `find`, but instead returns an array of `DOMWrapper`.
+
+`Component.vue`:
+
+```vue
+
+
+
+ {{ number }}
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+test('findAll', () => {
+ const wrapper = mount(Component)
+
+ wrapper.findAll('[data-test="number"]') //=> found; returns array of DOMWrapper
+})
+```
+
+### `findComponent`
+
+Finds a Vue Component instance and returns a `VueWrapper` if one is found, otherwise returns `ErrorWrapper`.
+
+**Supported syntax:**
+
+- **querySelector** - `findComponent('.component')` - Matches standard query selector.
+- **Name** - `findComponent({ name: 'myComponent' })` - matches PascalCase, snake-case, camelCase
+- **ref** - `findComponent({ ref: 'dropdown' })` - Can be used only on direct ref children of mounted component
+- **SFC** - `findComponent(ImportedComponent)` - Pass an imported component directly.
+
+`Foo.vue`
+
+```vue
+
+
+ Foo
+
+
+
+
+```
+
+`Component.vue`:
+
+```vue
+
+
+ Span
+
+
+
+
+
+```
+
+`Component.spec.js`
+
+```js
+import Foo from '@/Foo.vue'
+
+test('findComponent', () => {
+ const wrapper = mount(Component)
+
+ // All the following queries would return a VueWrapper
+
+ // Using a standard querySelector query
+ wrapper.findComponent('.foo')
+ wrapper.findComponent('[data-test="foo"]')
+
+ // Using component's name
+ wrapper.findComponent({ name: 'Foo' })
+
+ // Using ref attribute. Can be used only on direct children of the mounted component
+ wrapper.findComponent({ ref: 'foo' })
+
+ // Using imported component
+ wrapper.findComponent(Foo)
+})
+```
+
+### `findAllComponents`
+
+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
+
+
+
+ {{ number }}
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+test('findAllComponents', () => {
+ const wrapper = mount(Component)
+
+ // Returns an array of VueWrapper
+ wrapper.findAllComponents('[data-test="number"]')
+})
+```
+
+### `get`
+
+Similar to `find`, `get` looks for an element and returns a `DOMWrapper` if one is found. Otherwise it throws an error. 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
+
+ Span
+ Span
+
+```
+
+`Component.spec.js`:
+
+```js
+test('get', () => {
+ const wrapper = mount(Component)
+
+ wrapper.get('span') //=> found; returns DOMWrapper
+ wrapper.get('[data-test="span"]') //=> found; returns DOMWrapper, fails if no matching element is found
+})
+```
+
+### `getComponent`
+
+Similar to `findComponent`, `getComponent` looks for a Vue Component instance and returns a `VueWrapper` if one is found. Otherwise it throws an error.
+
+**Supported syntax:**
+
+- **querySelector** - `getComponent('.component')` - Matches standard query selector.
+- **Name** - `getComponent({ name: 'myComponent' })` - matches PascalCase, snake-case, camelCase
+- **ref** - `getComponent({ ref: 'dropdown' })` - Can be used only on direct ref children of mounted component
+- **SFC** - `getComponent(ImportedComponent)` - Pass an imported component directly.
+
+`Foo.vue`
+
+```vue
+
+
+ Foo
+
+
+
+
+```
+
+`Component.vue`:
+
+```vue
+
+
+
+
+
+```
+
+`Component.spec.js`
+
+```js
+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 (via `outerHTML`) of an element. Useful for debugging.
+
+`Component.vue`:
+
+```vue
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+test('html', () => {
+ const wrapper = mount(Component)
+
+ console.log(wrapper.html()) //=>
+})
+```
+
+### `isVisible`
+
+Verify whether or not a found element is visible or not.
+
+```js
+test('isVisible', () => {
+ const Comp = {
+ template: `
`
+ }
+ const wrapper = mount(Comp)
+
+ expect(wrapper.find('span').isVisible()).toBe(false)
+})
+```
+
+### `props`
+
+Returns props applied on a Vue Component. This should be used mostly to assert props applied to a stubbed component.
+
+**Note:** Props on a normally mounted Vue Component should be asserted by their side effects on the DOM or other.
+
+`Component.vue`:
+
+```js
+// Foo.vue
+export default {
+ name: 'Foo',
+ props: {
+ truthy: Boolean,
+ object: Object,
+ string: String
+ }
+}
+```
+
+```vue
+
+
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+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'
+ })
+})
+```
+
+### `setData`
+
+Updates component data.
+
+::: tip
+You should use `await` when you call `setData` to ensure that Vue updates the DOM before you make an assertion.
+:::
+
+`Component.vue`:
+
+```js
+test('updates component data', async () => {
+ const Component = {
+ template: 'Count: {{ count }}
',
+ data: () => ({ count: 0 })
+ }
+
+ const wrapper = mount(Component)
+ expect(wrapper.html()).toContain('Count: 0')
+
+ await wrapper.setData({ count: 1 })
+
+ expect(wrapper.html()).toContain('Count: 1')
+})
+```
+
+Notice that `setData` does not allow setting new properties that are not
+defined in the component.
+
+Also, notice that `setData` does not modify composition API `setup()` data.
+
+### `setProps`
+
+Updates component props.
+
+::: tip
+You should use `await` when you call `setProps` to ensure that Vue updates the DOM before you make an assertion.
+:::
+
+`Component.vue`:
+
+```vue
+
+ {{ message }}
+
+
+
+```
+
+`Component.spec.js`
+
+```js
+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')
+})
+```
+
+### `setValue`
+
+Sets a value on DOM element. Including:
+
+- ` `
+ - `type="checkbox"` and `type="radio"` are detected and will have `element.checked` set
+- ``
+ - `` is detected and will have `element.selected` set
+
+::: tip
+You should use `await` when you call `setValue` to ensure that Vue updates the DOM before you make an assertion.
+:::
+
+`Component.vue`:
+
+```vue
+
+
+ The input has been checked!
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+test('checked', async () => {
+ const wrapper = mount(Component)
+
+ await wrapper.find('input').setValue(true)
+ expect(wrapper.find('div')).toBe(true)
+
+ await wrapper.find('input').setValue(false)
+ expect(wrapper.find('div')).toBe(false)
+})
+```
+
+### `text`
+
+Returns the text (via `textContent`) of an element.
+
+`Component.vue`:
+
+```vue
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+test('text', () => {
+ const wrapper = mount(Component)
+
+ expect(wrapper.find('p').text()).toBe('Hello world')
+})
+```
+
+### `trigger`
+
+::: tip
+Since events often cause a re-render, `trigger` returns `Vue.nextTick`. You should use `await` when you call `trigger` to ensure that Vue updates the DOM before you make an assertion.
+:::
+
+Triggers a DOM event, for example `click`, `submit` or `keyup`.
+
+`Component.vue`:
+
+```vue
+
+
+ Count: {{ count }}
+ Click me
+
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+test('trigger', async () => {
+ const wrapper = mount(Component)
+
+ await wrapper.find('button').trigger('click')
+
+ expect(wrapper.find('span').text()).toBe('Count: 1')
+})
+```
+
+Note that `trigger` accepts a second argument to pass options to the triggered Event:
+
+```js
+await wrapper.trigger('keydown', { keyCode: 65 })
+```
+
+### `unmount`
+
+Unmount the application from the DOM via Vue's `unmount` method. Only works on the root `VueWrapper` returned from `mount`. Useful for manual clean-up after tests.
+
+`Component.vue`:
+
+```vue
+
+
+
+```
+
+`Component.spec.js`:
+
+```js
+test('unmount', () => {
+ const wrapper = mount(Component)
+
+ wrapper.unmount() // removed from DOM
+})
+```
+
+## Wrapper properties
+
+### `vm`
+
+This is the `Vue` instance. You can access all of the [instance methods and properties of a vm](https://v3.vuejs.org/api/instance-properties.html) with `wrapper.vm`. This only exists on `VueWrapper`.
diff --git a/docs/guide/advanced/async-suspense.md b/docs/guide/advanced/async-suspense.md
new file mode 100644
index 000000000..399b85bcf
--- /dev/null
+++ b/docs/guide/advanced/async-suspense.md
@@ -0,0 +1,113 @@
+# Asynchronous Behavior
+
+You may have noticed some other parts of the guide using `await` when calling some methods on `wrapper`, such as `trigger` and `setValue`. What's that all about?
+
+You might know Vue updates reactively; when you change a value, the DOM is automatically updated to reflect the latest value. Vue does this _asynchronously_. In contrast, a test runner like Jest runs _synchronously_. This can cause some surprising results in tests. Let's look at some strategies to ensure Vue is updating the DOM as expected when we run our tests.
+
+## A Simple Example - Updating with `trigger`
+
+Let's re-use the `` component from [event handling]./event-handling) with one change; we now render the `count` in the `template`.
+
+```js
+const Counter = {
+ template: `
+ Count: {{ count }}
+ Increment
+ `,
+ data() {
+ return {
+ count: 0
+ }
+ },
+ methods: {
+ handleClick() {
+ this.count += 1
+ }
+ }
+}
+```
+
+Let's write a test to verify the `count` is increasing:
+
+```js
+test('increments by 1', () => {
+ const wrapper = mount(Counter)
+
+ wrapper.find('button').trigger('click')
+
+ expect(wrapper.html()).toContain('Count: 1')
+})
+```
+
+Surprisingly, this fails! The reason is although `count` is increased, Vue will not update the DOM until the next "tick" or "render cycle". For this reason, the assertion will be called before Vue updates the DOM. This has to do with the concept of "macrotasks", "microtasks" and the JavaScript Event Loop. You can read more details and see a simple example [here](https://javascript.info/event-loop#macrotasks-and-microtasks).
+
+Implementation details aside, how can we fix this? Vue actually provides a way for us to wait until the DOM is updated: `nextTick`:
+
+```js {7}
+import { nextTick } from 'vue'
+
+test('increments by 1', async () => {
+ const wrapper = mount(Counter)
+
+ wrapper.find('button').trigger('click')
+ await nextTick()
+
+ expect(wrapper.html()).toContain('Count: 1')
+})
+```
+
+Now the test will pass, because we ensure the next "tick" has executed updated the DOM before the assertion runs. Since `await nextTick()` is common, VTU provides a shortcut. Methods than cause the DOM to update, such as `trigger` and `setValue` return `nextTick`! So you can just `await` those directly:
+
+```js {4}
+test('increments by 1', async () => {
+ const wrapper = mount(Counter)
+
+ await wrapper.find('button').trigger('click')
+
+ expect(wrapper.html()).toContain('Count: 1')
+})
+```
+
+## Resolving Other Asynchronous Behavior
+
+`nextTick` is useful to ensure some change in reactivty data is reflected in the DOM before continuing the test. However, sometimes you may want to ensure other, non Vue-related asynchronous behavior is completed, too. A common example is a function that returns a `Promise` that will lead to a change in the DOM. Perhaps you mocked your `axios` HTTP client using `jest.mock`:
+
+```js
+jest.mock('axios', () => ({
+ get: () => Promise.resolve({ data: 'some mocked data!' })
+}))
+```
+
+In this case, Vue has no knowledge of the unresolved Promise, so calling `nextTick` will not work - your assertion may run before it is resolved. For scenarios like this, you can use `[flush-promises](https://www.npmjs.com/package/flush-promises)`, which causes all outstanding promises to resolve immediately.
+
+Let's see an example:
+
+```js
+import flushPromises from 'flush-promises'
+import axios from 'axios'
+
+jest.mock('axios', () => ({
+ get: () =>
+ new Promise((resolve) => {
+ resolve({ data: 'some mocked data!' })
+ })
+}))
+
+test('uses a mocked axios HTTP client and flush-promises', async () => {
+ // some component that makes a HTTP called in `created` using `axios`
+ const wrapper = mount(AxiosComponent)
+
+ await flushPromises() // axios promise is resolved immediately!
+
+ // assertions!
+})
+```
+
+> If you haven't tested Components with API requests before, you can learn more in [HTTP Requests]./http-requests).
+
+## Conclusion
+
+- Vue updates the DOM asynchronously; tests runner execute code synchronously.
+- Use `await nextTick()` to ensure the DOM has updated before the test continues
+- Functions that might update the DOM, like `trigger` and `setValue` return `nextTick`, so you should `await` them.
+- Use `flush-promises` to resolve any unresolved promises from non-Vue dependencies.
diff --git a/docs/guide/advanced/component-instance.md b/docs/guide/advanced/component-instance.md
new file mode 100644
index 000000000..044ab7c17
--- /dev/null
+++ b/docs/guide/advanced/component-instance.md
@@ -0,0 +1,5 @@
+# Component Instance
+
+Mostly `findComponent()`, `.props()` et al.
+
+Also why `.vm` is not available and yet another recommendation to test outputs instead of implementation details.
diff --git a/docs/guide/advanced/http-requests.md b/docs/guide/advanced/http-requests.md
new file mode 100644
index 000000000..e0ae7555c
--- /dev/null
+++ b/docs/guide/advanced/http-requests.md
@@ -0,0 +1,175 @@
+# Making HTTP requests
+
+Modern test runners already provide lots of great features when it comes to test HTTP requests. Thus, Vue Test Utils doesn't feature any unique tool to do so.
+
+However, it is an important feature to test, and there are a few gotchas we want to highlight.
+
+In this section, we explore some patterns to perform, mock, and assert HTTP requests.
+
+## A list of blog posts
+
+Let's start with a basic use case. The following `PostList` component renders a list of blog posts fetched from an external API. To get these posts, the component features a `button` element that triggers the request:
+
+```vue
+
+ Get posts
+
+
+
+
+```
+
+There are several things we need to do to test this component properly.
+
+Our first goal is to test this component **without actually reaching the API**. This would create a fragile and potentially slow test.
+
+Secondly, we need to assert that the component made the right call with the appropriate parameters. We won't be getting results from that API, but we still need to ensure we requested the right resources.
+
+Also, we need to make sure that the DOM has updated accordingly and displays the data. We do so by using `flushPromises()` from the npm package [flush-promises](https://github.com/kentor/flush-promises).
+
+```js
+import { mount } from '@vue/test-utils'
+import axios from 'axios'
+import flushPromises from 'flush-promises'
+import PostList from './PostList.vue'
+
+const fakePostList = [
+ { id: 1, title: 'title1' },
+ { id: 2, title: 'title2' }
+]
+
+// Following lines tell Jest to mock any call to `axios.get`
+// and to return `fakePostList` instead
+jest.mock('axios', () => ({
+ get: jest.fn(() => fakePostList)
+}))
+
+test('loads posts on button click', async () => {
+ const wrapper = mount(PostList)
+
+ await wrapper.get('button').trigger('click')
+
+ // Let's assert that we've called axios.get the right amount of times and
+ // with the right parameters.
+ expect(axios.get).toHaveBeenCalledTimes(1)
+ expect(axios.get).toHaveBeenCalledWith('/api/posts')
+
+ // Wait until the DOM updates.
+ await flushPromises()
+
+ // Finally, we make sure we've rendered the content from the API.
+ const posts = wrapper.findAll('[data-test="post"]')
+
+ expect(posts).toHaveLength(2)
+ expect(posts[0].text()).toContain('title1')
+ expect(posts[1].text()).toContain('title2')
+})
+```
+
+Notice how we awaited `flushPromises` and then interacted with the Component. We do so to ensure that the DOM has been updated before the assertions run.
+
+:::tip Alternatives to jest.mock()
+There are several ways of setting mocks in Jest. The one used in the example above is the simplest. For more powerful alternatives, you might want to check out [axios-mock-adapter](https://github.com/ctimmerm/axios-mock-adapter) or [msw](https://github.com/mswjs/msw), among others.
+:::
+
+### Asserting loading state
+
+Now, this `PostList` component is pretty useful, but it lacks some other awesome features. Let's expand it to make it display a fancy message while loading our posts!
+
+Also, let's disable the `` element while loading, too. We don't want users to keep sending requests while fetching!
+
+```vue {2,4,19,24,28}
+
+ Get posts
+
+ Loading your posts…
+
+
+
+
+```
+
+Let's write a test to assert that all the loading-related elements are rendered on time.
+
+```js
+test('displays loading state on button click', async () => {
+ const wrapper = mount(PostList)
+
+ // Notice that we run the following assertions before clicking on the button
+ // Here, the component should be in a "not loading" state.
+ expect(wrapper.find('[role="alert"]').exists()).toBe(false)
+ expect(wrapper.get('button').attributes()).not.toHaveProperty('disabled')
+
+ // Now let's trigger it as usual.
+ await wrapper.get('button').trigger('click')
+
+ // We assert for "Loading state" before flushing all promises.
+ expect(wrapper.find('[role="alert"]').exists()).toBe(true)
+ expect(wrapper.get('button').attributes()).toHaveProperty('disabled')
+
+ // As we did before, wait until the DOM updates.
+ await flushPromises()
+
+ // After that, we're back at a "not loading" state.
+ expect(wrapper.find('[role="alert"]').exists()).toBe(false)
+ expect(wrapper.get('button').attributes()).not.toHaveProperty('disabled')
+})
+```
+
+## HTTP requests from Vuex
+
+A typical scenario for more complex applications is to trigger a Vuex action that performs the HTTP request.
+
+This is no different from the example outlined above. We might want to load the store as is and mock services such as `axios`. This way, we're mocking our system's boundaries, thus achieving a higher degree of confidence in our tests.
+
+You can check out the [Testing Vuex](vuex.md) docs for more information on testing Vuex with Vue Test Utils.
+
+## Conclusion
+
+- Vue Test Utils does not require special tools to test HTTP requests. The only thing to take into account is that we're testing asynchronous behavior.
+- Tests must not depend on external services. Use mocking tools such as `jest.mock` to avoid it.
+- `flushPromises()` is a useful tool to make sure the DOM updates after an async operation.
+- Directly triggering HTTP requests by interacting with the component makes your test more resilient.
diff --git a/docs/guide/advanced/reusability-composition.md b/docs/guide/advanced/reusability-composition.md
new file mode 100644
index 000000000..46be49e28
--- /dev/null
+++ b/docs/guide/advanced/reusability-composition.md
@@ -0,0 +1,7 @@
+# Reusability & Composition
+
+Mostly:
+
+- `global.provide`.
+- `global.mixins`.
+- `global.directives`.
diff --git a/docs/guide/advanced/slots.md b/docs/guide/advanced/slots.md
new file mode 100644
index 000000000..ac305871a
--- /dev/null
+++ b/docs/guide/advanced/slots.md
@@ -0,0 +1,156 @@
+# Slots
+
+Vue Test Utils provides some useful features for testing components using `slots`.
+
+## A Simple Example
+
+You might have a generic `` component that uses a default slot to render some content. For example:
+
+```js
+const Layout = {
+ template: `
+
+
Welcome!
+
+
+
+
+
+ `
+}
+```
+
+You might want to write a test to ensure the default slot content is rendered. VTU provides the `slots` mounting option for this purpose:
+
+```js
+test('layout default slot', () => {
+ const wrapper = mount(Layout, {
+ slots: {
+ default: 'Main Content'
+ }
+ })
+
+ expect(wrapper.html()).toContain('Main Content')
+})
+```
+
+It passes! In this example, we are passing some text content to the default slot. If you want to be even more specific, and verify the default slot content is rendered inside ``, you could change the assertion:
+
+```js
+test('layout default slot', () => {
+ const wrapper = mount(Layout, {
+ slots: {
+ default: 'Main Content'
+ }
+ })
+
+ expect(wrapper.find('main').text()).toContain('Main Content')
+})
+```
+
+## Named Slots
+
+You may have more complex `` component with some named slots. For example:
+
+```js
+const Layout = {
+ template: `
+
+
+
+
+
+
+
+
+ `
+}
+```
+
+VTU also supports this. You can write a test as follows. Note that in this example we are passing HTML instead of text content to the slots.
+
+```js
+test('layout full page layout', () => {
+ const wrapper = mount(Layout, {
+ slots: {
+ header: 'Header
',
+ main: 'Main Content
',
+ footer: 'Footer
'
+ }
+ })
+
+ expect(wrapper.html()).toContain('Header
')
+ expect(wrapper.html()).toContain('Main Content
')
+ expect(wrapper.html()).toContain('Footer
')
+})
+```
+
+## Advanced Usage
+
+You can also pass a render function to a slot mounting option, or even an SFC imported from a `vue` file:
+
+```js
+import { h } from 'vue'
+import Header from './Header.vue'
+
+test('layout full page layout', () => {
+ const wrapper = mount(Layout, {
+ slots: {
+ header: Header
+ main: h('div', 'Main content')
+ footer: 'Footer
'
+ }
+ })
+
+ expect(wrapper.html()).toContain('Header
')
+ expect(wrapper.html()).toContain('Main Content
')
+ expect(wrapper.html()).toContain('Footer
')
+})
+```
+
+Note: passing a component using `{ template: '
}` is not supported. Use a HTML string, render function, plain text, or an SFC.
+
+## Scoped Slots
+
+[Scoped slots](https://v3.vuejs.org/v2/guide/component-slots.html#scoped-slots) and bindings are also supported.
+
+```js
+const ComponentWithSlots = {
+ template: `
+
+
+
+ `,
+ data() {
+ return {
+ msg: 'world'
+ }
+ }
+}
+
+test('scoped slots', () => {
+ const wrapper = mount(ComponentWithSlots, {
+ slots: {
+ scoped: `
+ Hello {{ params.msg }}
+
+ `
+ }
+ })
+
+ expect(wrapper.html()).toContain('Hello world')
+})
+```
+
+## Conclusion
+
+- Use the `slots` mounting option to test components using `` are rendering content correctly.
+- Content can either be a string, a render function or an imported SFC.
+- Use `default` for the default slot, and the correct name for a named slots.
+- scoped slots and the `#` shorthand is also supported.
diff --git a/docs/guide/advanced/stubs-shallow-mount.md b/docs/guide/advanced/stubs-shallow-mount.md
new file mode 100644
index 000000000..2076b6d2c
--- /dev/null
+++ b/docs/guide/advanced/stubs-shallow-mount.md
@@ -0,0 +1,216 @@
+# Stubs and Shallow Mount
+
+Vue Test Utils provides some advanced features for _stubbing_ components. A _stub_ is where you replace an existing implementation of a custom component with a dummy component that doesn't do anything at all, which can simplify an otherwise complex test. Let's see an example.
+
+## Stubbing a single child component
+
+A common example is when you would like to test something in a component that appears very high in the component hierarchy.
+
+In this example, we have an `` that renders a message, as well as a `FetchDataFromApi` component that makes an API call and renders its result.
+
+```js
+const FetchDataFromApi = {
+ name: 'FetchDataFromApi',
+ template: `
+ {{ result }}
+ `,
+ async mounted() {
+ const res = await axios.get('/api/info')
+ this.result = res.data
+ },
+ data() {
+ return {
+ result: ''
+ }
+ }
+}
+
+const App = {
+ components: {
+ FetchDataFromApi
+ },
+ template: `
+ Welcome to Vue.js 3
+
+ `
+}
+```
+
+We do not want to make the API call in this particular test, we just want to assert the message is rendered. In this case, we could use the `stubs`, which appears in the `global` mounting option.
+
+```js
+test('stubs component with custom template', () => {
+ const wrapper = mount(App, {
+ global: {
+ stubs: {
+ FetchDataFromApi: {
+ template: ' '
+ }
+ }
+ }
+ })
+
+ console.log(wrapper.html())
+ // Welcome to Vue.js 3
+
+ expect(wrapper.html()).toContain('Welcome to Vue.js 3')
+})
+```
+
+Notice that the template is showing ` ` where ` ` was? We replaced it with a stub - in this case, we provided our own implementation by passing in a `template`.
+
+You can also get a default stub, instead of providing your own:
+
+```js
+test('stubs component', () => {
+ const wrapper = mount(App, {
+ global: {
+ stubs: {
+ FetchDataFromApi: true
+ }
+ }
+ })
+
+ console.log(wrapper.html())
+ /*
+ Welcome to Vue.js 3
+
+ */
+
+ expect(wrapper.html()).toContain('Welcome to Vue.js 3')
+})
+```
+
+This will stub out _all_ the ` ` components in the entire render tree, regardless of what level they appear at. That's why it is in the `global` mounting option.
+
+## Stubbing all children components
+
+Sometimes you might want to stub out _all_ the custom components. For example you might have a component like this:
+
+```js
+const ComplexComponent = {
+ components: { ComplexA, ComplexB, ComplexC },
+ template: `
+ Welcome to Vue.js 3
+
+
+
+ `
+}
+```
+
+Imagine each of the `` does something complicated, and you are only interested in testing that the `