Skip to content

Commit 5cfab4f

Browse files
authored
Merge pull request #127 from dobromir-hristov/feature/improve-vtu-async-flow
Improve Vue Test Utils async workflow
2 parents 49de6de + a872c27 commit 5cfab4f

File tree

1 file changed

+133
-0
lines changed

1 file changed

+133
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
- Start Date: 2020.02.01
2+
- Target Major Version: VTU beta-0.3x/1.x
3+
- Reference Issues:
4+
- Implementation PR:
5+
6+
# Summary
7+
8+
Allows the Vue Test Utils APIs that trigger re-renders to be awaited. This makes asserting changes after re-renders easier.
9+
10+
# Basic example
11+
```js
12+
const wrapper = mount(Component)
13+
await wrapper.find('.element').trigger('click')
14+
expect(wrapper.emitted('event')).toBeTruthy()
15+
```
16+
# Motivation
17+
18+
With the removal of `sync` mode in Vue Test Utils `beta-29`, we now need to `await` for things like watchers or the template to re-render, before we make assertions.
19+
20+
This proposal aims to make it easier for developers to work with async tests, by allowing you to `await` calls like `trigger` or those that use it internally.
21+
22+
The proposal assumes the usage of `async/await` inside tests.
23+
24+
# Detailed design
25+
26+
The general idea is to return a promise resolving on `nextTick`, from actions that trigger async changes.
27+
28+
At this moment we need to manually `await` for the component to update. This leads to extra boilerplate, and is harder to grasp for beginners.
29+
30+
```js
31+
const wrapper = mount(Component)
32+
wrapper.find('.element').trigger('click')
33+
// we need to wait for the component to render
34+
await wrapper.vm.$nextTick()
35+
expect(wrapper.emitted('event')).toBeTruthy()
36+
```
37+
38+
The new API should look like:
39+
40+
```js
41+
const wrapper = mount(Component)
42+
await wrapper.find('.element').trigger('click')
43+
expect(wrapper.emitted('event')).toBeTruthy()
44+
```
45+
46+
With more complicated tests, the benefits are obvious:
47+
48+
```js
49+
await wrapper.find('.button').trigger('click')
50+
expect(wrapper.emitted('event')).toBeTruthy()
51+
52+
await wrapper.find('.country-option').setValue('US')
53+
expect(wrapper.find('.state').exists()).toBe(true)
54+
55+
await wrapper.find('.radio-option').setChecked()
56+
expect(wrapper.find('.finish').attributes('disabled')).toBeFalsy()
57+
```
58+
59+
**Methods that should return a promise, resolving on next tick:**
60+
61+
- trigger
62+
- setValue
63+
- setChecked
64+
- setData
65+
- setProps
66+
- setSelected
67+
- setValue
68+
69+
Most of the above helpers rely on trigger internally, so updating the majority of listed methods would be easy.
70+
71+
### Additional helpers
72+
73+
Currently we have seen 3 ways to await for changes:
74+
75+
```js
76+
import flushPromises from 'flush-promises'
77+
await flushPromises()
78+
// or the more preferred
79+
await wrapper.vm.$nextTick()
80+
await Vue.nextTick()
81+
```
82+
83+
In Vue 3 `nextTick` will be removed from the VM instance, so users will have to migrate over to importing it from Vue directly `import { nextTick } from 'vue'`.
84+
85+
A `tick` helper can be added to the VTU exports. That way users have everything in one place, and an official way to await for renders, from actions that cannot directly return a promise.
86+
87+
Such a case is triggering a custom Vue event.
88+
89+
```js
90+
import { mount, tick } from '@vue/test-utils'
91+
92+
it('test' => {
93+
const wrapper = mount(Component)
94+
wrapper.find('.input').vm.$emit('input', 'Newly added note')
95+
await tick()
96+
97+
expect(wrapper).toMatchSnapshot()
98+
})
99+
```
100+
101+
Or we could be focusing an element on mounted, which is usually done on next tick
102+
103+
```js
104+
const wrapper = mount(Component)
105+
// await data to be focused on mounted
106+
await tick()
107+
let input = wrapper.find('input').element
108+
expect(input).toBe(document.activeElement)
109+
```
110+
111+
# Drawbacks
112+
113+
Each `trigger` will now call `nextTick()` , which I am not sure if it can hurt performance.
114+
115+
Users may try to `await` anything that interacts with the DOM, so it is a matter of writing good DOCs and guides on the topic.
116+
117+
# Alternatives
118+
119+
# Adoption strategy
120+
121+
### Vue Test Utils beta-30+
122+
123+
Users would have to make sure `async/await` is working in their testing env.
124+
125+
Users just have to remove extra `$nextTick` and `flushPromises` calls and use the new api.
126+
127+
Improve docs on the topic.
128+
129+
### Vue Test Utils prior to beta-30
130+
131+
Before the removal of `sync` mode it was not necessary to await for renders.
132+
133+
# Unresolved questions

0 commit comments

Comments
 (0)