Skip to content

Notes about 1.0.0-beta.30 #1375

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 18, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 117 additions & 3 deletions docs/guides/common-tips.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ const wrapper = shallowMount(Component)
wrapper.vm // the mounted Vue instance
```

### Using `nextTick`
### Writing asynchronous tests using `nextTick` (new)

Vue batches watcher updates and runs them asynchronously on the "next tick".
By default, Vue batches updates to run asynchronously (on the next "tick"). This is to prevent unnecessary DOM re-renders, and watcher computations ([see the docs](https://vuejs.org/v2/guide/reactivity.html#Async-Update-Queue) for more details).

In practice, this means you must wait for updates to run after you set a reactive property. You can wait for updates with `Vue.nextTick()`:
This means you **must** wait for updates to run after you set a reactive property. You can wait for updates with `Vue.nextTick()`:

```js
it('updates text', async () => {
Expand All @@ -40,6 +40,20 @@ it('updates text', async () => {
await Vue.nextTick()
expect(wrapper.text()).toContain('updated')
})

// Or if you're without async/await
it('render text', done => {
const wrapper = mount(TestComponent)
wrapper.trigger('click')
Vue.nextTick(() => {
wrapper.text().toContain('some text')
wrapper.trigger('click')
Vue.nextTick(() => {
wrapper.text().toContain('some different text')
done()
})
})
})
```

The following methods often cause watcher updates that require you to wait for the next tick:
Expand Down Expand Up @@ -160,6 +174,106 @@ You can also update the props of an already-mounted component with the `wrapper.

_For a full list of options, please see the [mount options section](../api/options.md) of the docs._

### Mocking Transitions

Although calling `await Vue.nextTick()` works well for most use cases, there are some situations where additional workarounds are required. These issues will be solved before the `vue-test-utils` library moves out of beta. One such example is unit testing components with the `<transition>` wrapper provided by Vue.

```vue
<template>
<div>
<transition>
<p v-if="show">Foo</p>
</transition>
</div>
</template>

<script>
export default {
data() {
return {
show: true
}
}
}
</script>
```

You might want to write a test that verifies that Foo is shown, then when `show` is set to `false`, Foo is no longer rendered. Such a test could be written as follows:

```js
test('should render Foo, then hide it', async () => {
const wrapper = mount(Foo)
expect(wrapper.text()).toMatch(/Foo/)

wrapper.setData({
show: false
})
await wrapper.vm.$nextTick()

expect(wrapper.text()).not.toMatch(/Foo/)
})
```

In practice, although we are calling `setData` then waiting for the `nextTick` to ensure the DOM is updated, this test fails. This is an ongoing issue related to show Vue implements the `<transition>` component, that we would like to solve before version 1.0. For now, there are some workarounds:

#### Using a `transitionStub` helper

```js
const transitionStub = () => ({
render: function(h) {
return this.$options._renderChildren
}
})

test('should render Foo, then hide it', async () => {
const wrapper = mount(Foo, {
stubs: {
transition: transitionStub()
}
})
expect(wrapper.text()).toMatch(/Foo/)

wrapper.setData({
show: false
})
await wrapper.vm.$nextTick()

expect(wrapper.text()).not.toMatch(/Foo/)
})
```

This overrides the default behavior of the `<transition>` component and renders the children as soon as the relevant boolean condition changes, as opposed to applying CSS classes, which is how Vue's `<transition>` component works.

#### Avoid `setData`

Another alternative is to simply avoid using `setData` by writing two tests, with the required setup performed using `mount` or `shallowMount` options:

```js
test('should render Foo', async () => {
const wrapper = mount(Foo, {
data() {
return {
show: true
}
}
})

expect(wrapper.text()).toMatch(/Foo/)
})

test('should not render Foo', async () => {
const wrapper = mount(Foo, {
data() {
return {
show: false
}
}
})

expect(wrapper.text()).not.toMatch(/Foo/)
})
```

### Applying Global Plugins and Mixins

Some of the components may rely on features injected by a global plugin or mixin, for example `vuex` and `vue-router`.
Expand Down