You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
### Writing asynchronous tests using `nextTick` (new)
31
31
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).
33
33
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()`:
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.
160
174
161
175
_For a full list of options, please see the [mount options section](../api/options.md) of the docs._
162
176
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
+
constwrapper=mount(Foo)
206
+
expect(wrapper.text()).toMatch(/Foo/)
207
+
208
+
wrapper.setData({
209
+
show:false
210
+
})
211
+
awaitwrapper.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
+
consttransitionStub= () => ({
223
+
render:function(h) {
224
+
returnthis.$options._renderChildren
225
+
}
226
+
})
227
+
228
+
test('should render Foo, then hide it', async () => {
229
+
constwrapper=mount(Foo, {
230
+
stubs: {
231
+
transition:transitionStub()
232
+
}
233
+
})
234
+
expect(wrapper.text()).toMatch(/Foo/)
235
+
236
+
wrapper.setData({
237
+
show:false
238
+
})
239
+
awaitwrapper.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
+
constwrapper=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
+
constwrapper=mount(Foo, {
266
+
data() {
267
+
return {
268
+
show:false
269
+
}
270
+
}
271
+
})
272
+
273
+
expect(wrapper.text()).not.toMatch(/Foo/)
274
+
})
275
+
```
276
+
163
277
### Applying Global Plugins and Mixins
164
278
165
279
Some of the components may rely on features injected by a global plugin or mixin, for example `vuex` and `vue-router`.
0 commit comments