Skip to content

Commit 5a4813b

Browse files
Kent C. Doddseps1lon
Kent C. Dodds
andauthored
docs: update async utility (#394)
* update async utility documentation for next major * Update docs/dom-testing-library/api-async.md Co-authored-by: Sebastian Silbermann <[email protected]>
1 parent 41ab33b commit 5a4813b

File tree

1 file changed

+84
-117
lines changed

1 file changed

+84
-117
lines changed

docs/dom-testing-library/api-async.md

+84-117
Original file line numberDiff line numberDiff line change
@@ -7,116 +7,103 @@ Several utilities are provided for dealing with asynchronous code. These can be
77
useful to wait for an element to appear or disappear in response to an action.
88
(See the [guide to testing disappearance](guide-disappearance.md).)
99

10+
All the async utils are built on top of `wait`.
11+
1012
## `wait`
1113

1214
```typescript
13-
function wait(
14-
callback?: () => void,
15+
function wait<T>(
16+
callback: () => void,
1517
options?: {
18+
container?: HTMLElement
1619
timeout?: number
1720
interval?: number
21+
mutationObserverOptions?: MutationObserverInit
1822
}
19-
): Promise<void>
23+
): Promise<T>
2024
```
2125

22-
When in need to wait for non-deterministic periods of time you can use `wait`,
23-
to wait for your expectations to pass. The `wait` function is a small wrapper
24-
around the
25-
[`wait-for-expect`](https://github.com/TheBrainFamily/wait-for-expect) module.
26-
Here's a simple example:
26+
When in need to wait for any period of time you can use `wait`, to wait for your
27+
expectations to pass. Here's a simple example:
2728

2829
```javascript
2930
// ...
3031
// Wait until the callback does not throw an error. In this case, that means
3132
// it'll wait until we can get a form control with a label that matches "username".
32-
await wait(() => getByLabelText(container, 'username'))
33-
getByLabelText(container, 'username').value = 'chucknorris'
33+
await wait(() => expect(mockAPI).toHaveBeenCalledTimes(1))
3434
// ...
3535
```
3636

3737
This can be useful if you have a unit test that mocks API calls and you need to
3838
wait for your mock promises to all resolve.
3939

40-
The default `callback` is a no-op function (used like `await wait()`). This can
41-
be helpful if you only need to wait for one tick of the event loop (in the case
42-
of mocked API calls with promises that resolve immediately).
43-
44-
The default `timeout` is `4500ms` which will keep you under
45-
[Jest's default timeout of `5000ms`](https://facebook.github.io/jest/docs/en/jest-object.html#jestsettimeouttimeout).
40+
The default `container` is the global `document`. Make sure the elements you
41+
wait for are descendants of `container`.
4642

4743
The default `interval` is `50ms`. However it will run your callback immediately
48-
on the next tick of the event loop (in a `setTimeout`) before starting the
49-
intervals.
44+
before starting the intervals.
45+
46+
The default `timeout` is `1000ms` which will keep you under
47+
[Jest's default timeout of `5000ms`](https://jestjs.io/docs/en/jest-object.html#jestsettimeouttimeout).
48+
49+
<a name="mutationobserveroptions"></a>The default `mutationObserverOptions` is
50+
`{subtree: true, childList: true, attributes: true, characterData: true}` which
51+
will detect additions and removals of child elements (including text nodes) in
52+
the `container` and any of its descendants. It will also detect attribute
53+
changes. When any of those changes occur, it will re-run the callback.
5054

51-
## `waitForElement`
55+
## `waitForElementToBeRemoved`
5256

5357
```typescript
54-
function waitForElement<T>(
55-
callback: () => T,
58+
function waitForElementToBeRemoved<T>(
59+
callback: (() => T) | T,
5660
options?: {
5761
container?: HTMLElement
5862
timeout?: number
63+
interval?: number
5964
mutationObserverOptions?: MutationObserverInit
6065
}
6166
): Promise<T>
6267
```
6368

64-
When in need to wait for DOM elements to appear, disappear, or change you can
65-
use `waitForElement`. The `waitForElement` function is a small wrapper around
66-
the
67-
[`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver).
69+
To wait for the removal of element(s) from the DOM you can use
70+
`waitForElementToBeRemoved`. The `waitForElementToBeRemoved` function is a small
71+
wrapper around the `wait` utility.
6872

69-
Here's a simple example:
73+
The first argument must be an element, array of elements, or a callback which returns
74+
an element or array of elements.
75+
76+
Here is an example where the promise resolves with `true` because the element is
77+
removed:
7078

7179
```javascript
72-
// ...
73-
// Wait until the callback does not throw an error and returns a truthy value. In this case, that means
74-
// it'll wait until we can get a form control with a label that matches "username".
75-
// The difference from `wait` is that rather than running your callback on
76-
// an interval, it's run as soon as there are DOM changes in the container
77-
// and returns the value returned by the callback.
78-
const usernameElement = await waitForElement(
79-
() => getByLabelText(container, 'username'),
80-
{ container }
81-
)
82-
usernameElement.value = 'chucknorris'
83-
// ...
84-
```
80+
const el = document.querySelector('div.getOuttaHere')
8581

86-
You can also wait for multiple elements at once:
82+
waitForElementToBeRemoved(document.querySelector('div.getOuttaHere'))
83+
.then(() => console.log('Element no longer in DOM'))
8784

88-
```javascript
89-
const [usernameElement, passwordElement] = await waitForElement(
90-
() => [
91-
getByLabelText(container, 'username'),
92-
getByLabelText(container, 'password'),
93-
],
94-
{ container }
95-
)
85+
el.setAttribute('data-neat', true)
86+
// other mutations are ignored...
87+
88+
el.parentElement.removeChild(el)
89+
// logs 'Element no longer in DOM'
9690
```
9791

98-
Using
99-
[`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver)
100-
is more efficient than polling the DOM at regular intervals with `wait`. This
101-
library sets up a
102-
[`'mutationobserver-shim'`](https://github.com/megawac/MutationObserver.js) on
103-
the global `window` object for cross-platform compatibility with older browsers
104-
and the [`jsdom`](https://github.com/jsdom/jsdom/issues/639) that is usually
105-
used in Node-based tests.
92+
`waitForElementToBeRemoved` will throw an error if the first argument is `null`
93+
or an empty array:
10694

107-
The default `container` is the global `document`. Make sure the elements you
108-
wait for will be attached to it, or set a different `container`.
95+
```javascript
96+
waitForElementToBeRemoved(null).catch(err => console.log(err))
97+
waitForElementToBeRemoved(queryByText(/not here/i)).catch(err => console.log(err))
98+
waitForElementToBeRemoved(queryAllByText(/not here/i)).catch(err => console.log(err))
99+
waitForElementToBeRemoved(() => getByText(/not here/i)).catch(err => console.log(err))
109100

110-
The default `timeout` is `4500ms` which will keep you under
111-
[Jest's default timeout of `5000ms`](https://facebook.github.io/jest/docs/en/jest-object.html#jestsettimeouttimeout).
101+
// Error: The element(s) given to waitForElementToBeRemoved are already removed. waitForElementToBeRemoved requires that the element(s) exist(s) before waiting for removal.
102+
```
112103

113-
<a name="mutationobserveroptions"></a>The default `mutationObserverOptions` is
114-
`{subtree: true, childList: true, attributes: true, characterData: true}` which
115-
will detect additions and removals of child elements (including text nodes) in
116-
the `container` and any of its descendants. It will also detect attribute
117-
changes.
104+
The options object is forwarded to `wait`.
118105

119-
## `waitForDomChange`
106+
## `waitForDomChange` (DEPRECATED, use wait instead)
120107

121108
```typescript
122109
function waitForDomChange<T>(options?: {
@@ -167,31 +154,23 @@ container.setAttribute('data-cool', 'false')
167154
*/
168155
```
169156

170-
Using
171-
[`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver)
172-
is more efficient than polling the DOM at regular intervals with `wait`. This
173-
library sets up a
174-
[`'mutationobserver-shim'`](https://github.com/megawac/MutationObserver.js) on
175-
the global `window` object for cross-platform compatibility with older browsers
176-
and the [`jsdom`](https://github.com/jsdom/jsdom/issues/639) that is usually
177-
used in Node-based tests.
178-
179157
The default `container` is the global `document`. Make sure the elements you
180-
wait for will be attached to it, or set a different `container`.
158+
wait for are descendants of `container`.
181159

182-
The default `timeout` is `4500ms` which will keep you under
183-
[Jest's default timeout of `5000ms`](https://facebook.github.io/jest/docs/en/jest-object.html#jestsettimeouttimeout).
160+
The default `timeout` is `1000ms` which will keep you under
161+
[Jest's default timeout of `5000ms`](https://jestjs.io/docs/en/jest-object.html#jestsettimeouttimeout).
184162

185163
<a name="mutationobserveroptions"></a>The default `mutationObserverOptions` is
186164
`{subtree: true, childList: true, attributes: true, characterData: true}` which
187165
will detect additions and removals of child elements (including text nodes) in
188166
the `container` and any of its descendants. It will also detect attribute
189167
changes.
190168

191-
## `waitForElementToBeRemoved`
169+
170+
## `waitForElement` (DEPRECATED, use `find*` queries or `wait`)
192171

193172
```typescript
194-
function waitForElementToBeRemoved<T>(
173+
function waitForElement<T>(
195174
callback: () => T,
196175
options?: {
197176
container?: HTMLElement
@@ -201,54 +180,42 @@ function waitForElementToBeRemoved<T>(
201180
): Promise<T>
202181
```
203182

204-
To wait for the removal of element(s) from the DOM you can use
205-
`waitForElementToBeRemoved`. The `waitForElementToBeRemoved` function is a small
206-
wrapper around the
183+
When in need to wait for DOM elements to appear, disappear, or change you can
184+
use `waitForElement`. The `waitForElement` function is a small wrapper around
185+
the
207186
[`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver).
208187

209-
The callback must return the pre-existing element or array of elements that are
210-
expected to be removed.
211-
212-
Here is an example where the promise resolves with `true` because the element is
213-
removed:
188+
Here's a simple example:
214189

215190
```javascript
216-
const el = document.querySelector('div.getOuttaHere')
217-
218-
waitForElementToBeRemoved(() =>
219-
document.querySelector('div.getOuttaHere')
220-
).then(() => console.log('Element no longer in DOM'))
221-
222-
el.setAttribute('data-neat', true)
223-
// other mutations are ignored...
224-
225-
el.parentElement.removeChild(el)
226-
// logs 'Element no longer in DOM'
191+
// ...
192+
// Wait until the callback does not throw an error and returns a truthy value. In this case, that means
193+
// it'll wait until we can get a form control with a label that matches "username".
194+
// The difference from `wait` is that rather than running your callback on
195+
// an interval, it's run as soon as there are DOM changes in the container
196+
// and returns the value returned by the callback.
197+
const usernameElement = await waitForElement(
198+
() => getByLabelText(container, 'username'),
199+
{ container }
200+
)
201+
usernameElement.value = 'chucknorris'
202+
// ...
227203
```
228204

229-
`waitForElementToBeRemoved` will throw an error when the provided callback does
230-
not return an element.
205+
You can also wait for multiple elements at once:
231206

232207
```javascript
233-
waitForElementToBeRemoved(() => null).catch(err => console.log(err))
234-
235-
// 'The callback function which was passed did not return an element
236-
// or non-empty array of elements.
237-
// waitForElementToBeRemoved requires that the element(s) exist
238-
// before waiting for removal.'
208+
const [usernameElement, passwordElement] = await waitForElement(
209+
() => [
210+
getByLabelText(container, 'username'),
211+
getByLabelText(container, 'password'),
212+
],
213+
{ container }
214+
)
239215
```
240216

241-
Using
242-
[`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver)
243-
is more efficient than polling the DOM at regular intervals with `wait`. This
244-
library sets up a
245-
[`'mutationobserver-shim'`](https://github.com/megawac/MutationObserver.js) on
246-
the global `window` object for cross-platform compatibility with older browsers
247-
and the [`jsdom`](https://github.com/jsdom/jsdom/issues/639) that is usually
248-
used in Node-based tests.
249-
250217
The default `container` is the global `document`. Make sure the elements you
251-
wait for are descendants of `container`.
218+
wait for will be attached to it, or set a different `container`.
252219

253220
The default `timeout` is `4500ms` which will keep you under
254221
[Jest's default timeout of `5000ms`](https://facebook.github.io/jest/docs/en/jest-object.html#jestsettimeouttimeout).

0 commit comments

Comments
 (0)