Skip to content

Commit d9f01ae

Browse files
committed
feat: use default values for interval and timeout in async utils
BREAKING CHANGE: `interval` will now default to 50ms in async utils BREAKING CHANGE: `timeout` will now default to 1000ms in async utils BREAKING CHANGE: `suppressErrors` has been removed from async utils
1 parent bab38d9 commit d9f01ae

File tree

7 files changed

+385
-356
lines changed

7 files changed

+385
-356
lines changed

docs/api-reference.md

+18-24
Original file line numberDiff line numberDiff line change
@@ -201,25 +201,26 @@ removed, the provided callback will no longer execute as part of running
201201
### `waitForNextUpdate`
202202

203203
```ts
204-
function waitForNextUpdate(options?: { timeout?: number }): Promise<void>
204+
function waitForNextUpdate(options?: { timeout?: number | false }): Promise<void>
205205
```
206206

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

210210
#### `timeout`
211211

212-
The maximum amount of time in milliseconds (ms) to wait. By default, no timeout is applied.
212+
_Default: 1000_
213+
214+
The maximum amount of time in milliseconds (ms) to wait.
213215

214216
### `waitFor`
215217

216218
```ts
217219
function waitFor(
218220
callback: () => boolean | void,
219221
options?: {
220-
interval?: number
221-
timeout?: number
222-
suppressErrors?: boolean
222+
interval?: number | false
223+
timeout?: number | false
223224
}
224225
): Promise<void>
225226
```
@@ -230,29 +231,25 @@ in the callback to perform assertion or to test values.
230231

231232
#### `interval`
232233

234+
_Default: 50_
235+
233236
The amount of time in milliseconds (ms) to wait between checks of the callback if no renders occur.
234-
Interval checking is disabled if `interval` is not provided in the options or provided as a `falsy`
235-
value. By default, it is disabled.
237+
Interval checking is disabled if `interval` is not provided as a `falsy`.
236238

237239
#### `timeout`
238240

239-
The maximum amount of time in milliseconds (ms) to wait. By default, no timeout is applied.
240-
241-
#### `suppressErrors`
241+
_Default: 1000_
242242

243-
If this option is set to `true`, any errors that occur while waiting are treated as a failed check.
244-
If this option is set to `false`, any errors that occur while waiting cause the promise to be
245-
rejected. By default, errors are suppressed for this utility.
243+
The maximum amount of time in milliseconds (ms) to wait.
246244

247245
### `waitForValueToChange`
248246

249247
```ts
250248
function waitForValueToChange(
251249
selector: () => any,
252250
options?: {
253-
interval?: number
254-
timeout?: number
255-
suppressErrors?: boolean
251+
interval?: number | false
252+
timeout?: number | false
256253
}
257254
): Promise<void>
258255
```
@@ -263,16 +260,13 @@ for comparison.
263260

264261
#### `interval`
265262

263+
_Default: 50_
264+
266265
The amount of time in milliseconds (ms) to wait between checks of the callback if no renders occur.
267-
Interval checking is disabled if `interval` is not provided in the options or provided as a `falsy`
268-
value. By default, it is disabled.
266+
Interval checking is disabled if `interval` is not provided as a `falsy`.
269267

270268
#### `timeout`
271269

272-
The maximum amount of time in milliseconds (ms) to wait. By default, no timeout is applied.
273-
274-
#### `suppressErrors`
270+
_Default: 1000_
275271

276-
If this option is set to `true`, any errors that occur while waiting are treated as a failed check.
277-
If this option is set to `false`, any errors that occur while waiting cause the promise to be
278-
rejected. By default, errors are not suppressed for this utility.
272+
The maximum amount of time in milliseconds (ms) to wait.

src/core/asyncUtils.ts

+80-61
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,116 @@
1-
import { Act, WaitOptions, AsyncUtils } from '../types'
1+
import {
2+
Act,
3+
WaitOptions,
4+
WaitForOptions,
5+
WaitForValueToChangeOptions,
6+
WaitForNextUpdateOptions,
7+
AsyncUtils
8+
} from '../types'
29

310
import { resolveAfter } from '../helpers/promises'
411
import { TimeoutError } from '../helpers/error'
512

6-
function asyncUtils(act: Act, addResolver: (callback: () => void) => void): AsyncUtils {
7-
let nextUpdatePromise: Promise<void> | null = null
8-
9-
const waitForNextUpdate = async ({ timeout }: Pick<WaitOptions, 'timeout'> = {}) => {
10-
if (nextUpdatePromise) {
11-
await nextUpdatePromise
12-
} else {
13-
nextUpdatePromise = new Promise((resolve, reject) => {
14-
let timeoutId: ReturnType<typeof setTimeout>
15-
if (timeout && timeout > 0) {
16-
timeoutId = setTimeout(
17-
() => reject(new TimeoutError(waitForNextUpdate, timeout)),
18-
timeout
19-
)
20-
}
21-
addResolver(() => {
22-
clearTimeout(timeoutId)
23-
nextUpdatePromise = null
24-
resolve()
25-
})
26-
})
27-
await act(() => nextUpdatePromise as Promise<void>)
28-
}
29-
}
13+
const DEFAULT_INTERVAL = 50
14+
const DEFAULT_TIMEOUT = 1000
3015

31-
const waitFor = async (
16+
function asyncUtils(act: Act, addResolver: (callback: () => void) => void): AsyncUtils {
17+
const wait = async (
3218
callback: () => boolean | void,
33-
{ interval, timeout, suppressErrors = true }: WaitOptions = {}
19+
{ interval = DEFAULT_INTERVAL, timeout = DEFAULT_TIMEOUT }: WaitOptions = {}
3420
) => {
3521
const checkResult = () => {
36-
try {
37-
const callbackResult = callback()
38-
return callbackResult ?? callbackResult === undefined
39-
} catch (error: unknown) {
40-
if (!suppressErrors) {
41-
throw error
42-
}
43-
return undefined
44-
}
22+
const callbackResult = callback()
23+
return callbackResult ?? callbackResult === undefined
4524
}
4625

4726
const waitForResult = async () => {
48-
const initialTimeout = timeout
4927
while (true) {
50-
const startTime = Date.now()
51-
try {
52-
const nextCheck = interval
53-
? Promise.race([waitForNextUpdate({ timeout }), resolveAfter(interval)])
54-
: waitForNextUpdate({ timeout })
55-
56-
await nextCheck
28+
await Promise.race(
29+
[
30+
new Promise<void>((resolve) => addResolver(resolve)),
31+
interval && resolveAfter(interval)
32+
].filter(Boolean)
33+
)
5734

58-
if (checkResult()) {
59-
return
60-
}
61-
} catch (error: unknown) {
62-
if (error instanceof TimeoutError && initialTimeout) {
63-
throw new TimeoutError(waitFor, initialTimeout)
64-
}
65-
throw error
35+
if (checkResult()) {
36+
return
6637
}
67-
if (timeout) timeout -= Date.now() - startTime
6838
}
6939
}
7040

7141
if (!checkResult()) {
72-
await waitForResult()
42+
if (timeout) {
43+
const timeoutPromise = new Promise<void>((resolve, reject) => {
44+
if (timeout) {
45+
setTimeout(() => reject(new TimeoutError(wait, timeout)), timeout)
46+
} else {
47+
resolve()
48+
}
49+
})
50+
51+
await act(() => Promise.race([waitForResult(), timeoutPromise]))
52+
} else {
53+
await act(waitForResult)
54+
}
7355
}
7456
}
7557

76-
const waitForValueToChange = async (selector: () => unknown, options: WaitOptions = {}) => {
58+
const waitFor = async (callback: () => boolean | void, options: WaitForOptions = {}) => {
59+
const safeCallback = () => {
60+
try {
61+
return callback()
62+
} catch (error: unknown) {
63+
return false
64+
}
65+
}
66+
try {
67+
await wait(safeCallback, options)
68+
} catch (error: unknown) {
69+
if (error instanceof TimeoutError) {
70+
throw new TimeoutError(waitFor, error.timeout)
71+
}
72+
throw error
73+
}
74+
}
75+
76+
const waitForValueToChange = async (
77+
selector: () => unknown,
78+
options: WaitForValueToChangeOptions = {}
79+
) => {
7780
const initialValue = selector()
7881
try {
79-
await waitFor(() => selector() !== initialValue, {
80-
suppressErrors: false,
82+
await wait(() => selector() !== initialValue, options)
83+
} catch (error: unknown) {
84+
if (error instanceof TimeoutError) {
85+
throw new TimeoutError(waitForValueToChange, error.timeout)
86+
}
87+
throw error
88+
}
89+
}
90+
91+
const waitForNextUpdate = async (options: WaitForNextUpdateOptions = {}) => {
92+
let updated = false
93+
addResolver(() => {
94+
updated = true
95+
})
96+
97+
try {
98+
await wait(() => updated, {
99+
interval: false,
81100
...options
82101
})
83102
} catch (error: unknown) {
84-
if (error instanceof TimeoutError && options.timeout) {
85-
throw new TimeoutError(waitForValueToChange, options.timeout)
103+
if (error instanceof TimeoutError) {
104+
throw new TimeoutError(waitForNextUpdate, error.timeout)
86105
}
87106
throw error
88107
}
89108
}
90109

91110
return {
92111
waitFor,
93-
waitForNextUpdate,
94-
waitForValueToChange
112+
waitForValueToChange,
113+
waitForNextUpdate
95114
}
96115
}
97116

0 commit comments

Comments
 (0)