Skip to content

Commit 50c9720

Browse files
authored
Merge pull request #408 from testing-library/pr/wait-intervals
Add interval to async utilities to supplement post render checks
2 parents b7a2103 + 1ddafa2 commit 50c9720

File tree

3 files changed

+247
-35
lines changed

3 files changed

+247
-35
lines changed

docs/api-reference.md

+59-18
Original file line numberDiff line numberDiff line change
@@ -152,50 +152,92 @@ variable to `true` before importing `@testing-library/react-hooks` will also dis
152152
### `waitForNextUpdate`
153153
154154
```js
155-
function waitForNextUpdate(options?: WaitOptions): Promise<void>
155+
function waitForNextUpdate(options?: {
156+
timeout?: number
157+
}): Promise<void>
156158
```
157159

158160
Returns a `Promise` that resolves the next time the hook renders, commonly when state is updated as
159161
the result of an asynchronous update.
160162

161-
See the [`wait` Options](/reference/api#wait-options) section for more details on the available
162-
`options`.
163+
#### `timeout`
163164

164-
### `wait`
165+
The maximum amount of time in milliseconds (ms) to wait. By default, no timeout is applied.
166+
167+
### `waitFor`
165168

166169
```js
167-
function wait(callback: function(): boolean|void, options?: WaitOptions): Promise<void>
170+
function waitFor(callback: function(): boolean|void, options?: {
171+
interval?: number,
172+
timeout?: number,
173+
suppressErrors?: boolean
174+
}): Promise<void>
168175
```
169176

170177
Returns a `Promise` that resolves if the provided callback executes without exception and returns a
171178
truthy or `undefined` value. It is safe to use the [`result` of `renderHook`](/reference/api#result)
172179
in the callback to perform assertion or to test values.
173180

174-
The callback is tested after each render of the hook. By default, errors raised from the callback
175-
will be suppressed (`suppressErrors = true`).
181+
#### `interval`
176182

177-
See the [`wait` Options](/reference/api#wait-options) section for more details on the available
178-
`options`.
183+
The amount of time in milliseconds (ms) to wait between checks of the callback if no renders occur.
184+
Interval checking is disabled if `interval` is not provided in the options or provided as a `falsy`
185+
value. By default, it is disabled.
186+
187+
#### `timeout`
188+
189+
The maximum amount of time in milliseconds (ms) to wait. By default, no timeout is applied.
190+
191+
#### `suppressErrors`
192+
193+
If this option is set to `true`, any errors that occur while waiting are treated as a failed check.
194+
If this option is set to `false`, any errors that occur while waiting cause the promise to be
195+
rejected. By default, errors are suppressed for this utility.
179196

180197
### `waitForValueToChange`
181198

182199
```js
183-
function waitForValueToChange(selector: function(): any, options?: WaitOptions): Promise<void>
200+
function waitForValueToChange(selector: function(): any, options?: {
201+
interval?: number,
202+
timeout?: number,
203+
suppressErrors?: boolean
204+
}): Promise<void>
184205
```
185206

186207
Returns a `Promise` that resolves if the value returned from the provided selector changes. It
187208
expected that the [`result` of `renderHook`](/reference/api#result) to select the value for
188209
comparison.
189210

190-
The value is selected for comparison after each render of the hook. By default, errors raised from
191-
selecting the value will not be suppressed (`suppressErrors = false`).
211+
#### `interval`
212+
213+
The amount of time in milliseconds (ms) to wait between checks of the callback if no renders occur.
214+
Interval checking is disabled if `interval` is not provided in the options or provided as a `falsy`
215+
value. By default, it is disabled.
216+
217+
#### `timeout`
218+
219+
The maximum amount of time in milliseconds (ms) to wait. By default, no timeout is applied.
220+
221+
#### `suppressErrors`
192222

193-
See the [`wait` Options](/reference/api#wait-options) section for more details on the available
194-
`options`.
223+
If this option is set to `true`, any errors that occur while waiting are treated as a failed check.
224+
If this option is set to `false`, any errors that occur while waiting cause the promise to be
225+
rejected. By default, errors are not suppressed for this utility.
195226

196-
### `wait` Options
227+
### `wait`
197228

198-
The async utilities accept the following options:
229+
_(DEPRECATED, use [`waitFor`](/reference/api#waitfor) instead)_
230+
231+
```js
232+
function wait(callback: function(): boolean|void, options?: {
233+
timeout?: number,
234+
suppressErrors?: boolean
235+
}): Promise<void>
236+
```
237+
238+
Returns a `Promise` that resolves if the provided callback executes without exception and returns a
239+
truthy or `undefined` value. It is safe to use the [`result` of `renderHook`](/reference/api#result)
240+
in the callback to perform assertion or to test values.
199241

200242
#### `timeout`
201243

@@ -205,5 +247,4 @@ The maximum amount of time in milliseconds (ms) to wait. By default, no timeout
205247

206248
If this option is set to `true`, any errors that occur while waiting are treated as a failed check.
207249
If this option is set to `false`, any errors that occur while waiting cause the promise to be
208-
rejected. Please refer to the [utility descriptions](/reference/api#async-utilities) for the default
209-
values of this option (if applicable).
250+
rejected. By default, errors are suppressed for this utility.

src/asyncUtils.js

+35-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ function createTimeoutError(utilName, { timeout }) {
66
return timeoutError
77
}
88

9+
function resolveAfter(ms) {
10+
return new Promise((resolve) => {
11+
setTimeout(resolve, ms)
12+
})
13+
}
14+
15+
let hasWarnedDeprecatedWait = false
16+
917
function asyncUtils(addResolver) {
1018
let nextUpdatePromise = null
1119

@@ -30,7 +38,7 @@ function asyncUtils(addResolver) {
3038
await nextUpdatePromise
3139
}
3240

33-
const wait = async (callback, { timeout, suppressErrors = true } = {}) => {
41+
const waitFor = async (callback, { interval, timeout, suppressErrors = true } = {}) => {
3442
const checkResult = () => {
3543
try {
3644
const callbackResult = callback()
@@ -47,13 +55,18 @@ function asyncUtils(addResolver) {
4755
while (true) {
4856
const startTime = Date.now()
4957
try {
50-
await waitForNextUpdate({ timeout })
58+
const nextCheck = interval
59+
? Promise.race([waitForNextUpdate({ timeout }), resolveAfter(interval)])
60+
: waitForNextUpdate({ timeout })
61+
62+
await nextCheck
63+
5164
if (checkResult()) {
5265
return
5366
}
5467
} catch (e) {
5568
if (e.timeout) {
56-
throw createTimeoutError('wait', { timeout: initialTimeout })
69+
throw createTimeoutError('waitFor', { timeout: initialTimeout })
5770
}
5871
throw e
5972
}
@@ -69,7 +82,7 @@ function asyncUtils(addResolver) {
6982
const waitForValueToChange = async (selector, options = {}) => {
7083
const initialValue = selector()
7184
try {
72-
await wait(() => selector() !== initialValue, {
85+
await waitFor(() => selector() !== initialValue, {
7386
suppressErrors: false,
7487
...options
7588
})
@@ -81,8 +94,26 @@ function asyncUtils(addResolver) {
8194
}
8295
}
8396

97+
const wait = async (callback, { timeout, suppressErrors } = {}) => {
98+
if (!hasWarnedDeprecatedWait) {
99+
hasWarnedDeprecatedWait = true
100+
console.warn(
101+
'`wait` has been deprecated. Use `waitFor` instead: https://react-hooks-testing-library.com/reference/api#waitfor.'
102+
)
103+
}
104+
try {
105+
await waitFor(callback, { timeout, suppressErrors })
106+
} catch (e) {
107+
if (e.timeout) {
108+
throw createTimeoutError('wait', { timeout })
109+
}
110+
throw e
111+
}
112+
}
113+
84114
return {
85115
wait,
116+
waitFor,
86117
waitForNextUpdate,
87118
waitForValueToChange
88119
}

0 commit comments

Comments
 (0)