Skip to content

Commit 79eab20

Browse files
authored
Merge pull request #1375 from JessicaSachs/docs/beta30-notes
Notes about 1.0.0-beta.30
2 parents d681e76 + dcfee27 commit 79eab20

File tree

1 file changed

+117
-3
lines changed

1 file changed

+117
-3
lines changed

docs/guides/common-tips.md

Lines changed: 117 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ const wrapper = shallowMount(Component)
2727
wrapper.vm // the mounted Vue instance
2828
```
2929

30-
### Using `nextTick`
30+
### Writing asynchronous tests using `nextTick` (new)
3131

32-
Vue batches watcher updates and runs them asynchronously on the "next tick".
32+
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).
3333

34-
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()`:
34+
This means you **must** wait for updates to run after you set a reactive property. You can wait for updates with `Vue.nextTick()`:
3535

3636
```js
3737
it('updates text', async () => {
@@ -40,6 +40,20 @@ it('updates text', async () => {
4040
await Vue.nextTick()
4141
expect(wrapper.text()).toContain('updated')
4242
})
43+
44+
// Or if you're without async/await
45+
it('render text', done => {
46+
const wrapper = mount(TestComponent)
47+
wrapper.trigger('click')
48+
Vue.nextTick(() => {
49+
wrapper.text().toContain('some text')
50+
wrapper.trigger('click')
51+
Vue.nextTick(() => {
52+
wrapper.text().toContain('some different text')
53+
done()
54+
})
55+
})
56+
})
4357
```
4458

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

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

177+
### Mocking Transitions
178+
179+
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.
180+
181+
```vue
182+
<template>
183+
<div>
184+
<transition>
185+
<p v-if="show">Foo</p>
186+
</transition>
187+
</div>
188+
</template>
189+
190+
<script>
191+
export default {
192+
data() {
193+
return {
194+
show: true
195+
}
196+
}
197+
}
198+
</script>
199+
```
200+
201+
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:
202+
203+
```js
204+
test('should render Foo, then hide it', async () => {
205+
const wrapper = mount(Foo)
206+
expect(wrapper.text()).toMatch(/Foo/)
207+
208+
wrapper.setData({
209+
show: false
210+
})
211+
await wrapper.vm.$nextTick()
212+
213+
expect(wrapper.text()).not.toMatch(/Foo/)
214+
})
215+
```
216+
217+
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:
218+
219+
#### Using a `transitionStub` helper
220+
221+
```js
222+
const transitionStub = () => ({
223+
render: function(h) {
224+
return this.$options._renderChildren
225+
}
226+
})
227+
228+
test('should render Foo, then hide it', async () => {
229+
const wrapper = mount(Foo, {
230+
stubs: {
231+
transition: transitionStub()
232+
}
233+
})
234+
expect(wrapper.text()).toMatch(/Foo/)
235+
236+
wrapper.setData({
237+
show: false
238+
})
239+
await wrapper.vm.$nextTick()
240+
241+
expect(wrapper.text()).not.toMatch(/Foo/)
242+
})
243+
```
244+
245+
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.
246+
247+
#### Avoid `setData`
248+
249+
Another alternative is to simply avoid using `setData` by writing two tests, with the required setup performed using `mount` or `shallowMount` options:
250+
251+
```js
252+
test('should render Foo', async () => {
253+
const wrapper = mount(Foo, {
254+
data() {
255+
return {
256+
show: true
257+
}
258+
}
259+
})
260+
261+
expect(wrapper.text()).toMatch(/Foo/)
262+
})
263+
264+
test('should not render Foo', async () => {
265+
const wrapper = mount(Foo, {
266+
data() {
267+
return {
268+
show: false
269+
}
270+
}
271+
})
272+
273+
expect(wrapper.text()).not.toMatch(/Foo/)
274+
})
275+
```
276+
163277
### Applying Global Plugins and Mixins
164278

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

0 commit comments

Comments
 (0)