1 | import { act } from 'react-test-renderer'
|
2 |
|
3 | function createTimeoutError(utilName, { timeout }) {
|
4 | const timeoutError = new Error(`Timed out in ${utilName} after ${timeout}ms.`)
|
5 | timeoutError.timeout = true
|
6 | return timeoutError
|
7 | }
|
8 |
|
9 | function asyncUtils(addResolver) {
|
10 | let nextUpdatePromise = null
|
11 |
|
12 | const waitForNextUpdate = async (options = {}) => {
|
13 | if (!nextUpdatePromise) {
|
14 | nextUpdatePromise = new Promise((resolve, reject) => {
|
15 | let timeoutId
|
16 | if (options.timeout > 0) {
|
17 | timeoutId = setTimeout(
|
18 | () => reject(createTimeoutError('waitForNextUpdate', options)),
|
19 | options.timeout
|
20 | )
|
21 | }
|
22 | addResolver(() => {
|
23 | clearTimeout(timeoutId)
|
24 | nextUpdatePromise = null
|
25 | resolve()
|
26 | })
|
27 | })
|
28 | await act(() => nextUpdatePromise)
|
29 | }
|
30 | await nextUpdatePromise
|
31 | }
|
32 |
|
33 | const wait = async (callback, { timeout, suppressErrors = true } = {}) => {
|
34 | const checkResult = () => {
|
35 | try {
|
36 | const callbackResult = callback()
|
37 | return callbackResult || callbackResult === undefined
|
38 | } catch (e) {
|
39 | if (!suppressErrors) {
|
40 | throw e
|
41 | }
|
42 | }
|
43 | }
|
44 |
|
45 | const waitForResult = async () => {
|
46 | const initialTimeout = timeout
|
47 | while (true) {
|
48 | const startTime = Date.now()
|
49 | try {
|
50 | await waitForNextUpdate({ timeout })
|
51 | if (checkResult()) {
|
52 | return
|
53 | }
|
54 | } catch (e) {
|
55 | if (e.timeout) {
|
56 | throw createTimeoutError('wait', { timeout: initialTimeout })
|
57 | }
|
58 | throw e
|
59 | }
|
60 | timeout -= Date.now() - startTime
|
61 | }
|
62 | }
|
63 |
|
64 | if (!checkResult()) {
|
65 | await waitForResult()
|
66 | }
|
67 | }
|
68 |
|
69 | const waitForValueToChange = async (selector, options = {}) => {
|
70 | const initialValue = selector()
|
71 | try {
|
72 | await wait(() => selector() !== initialValue, {
|
73 | suppressErrors: false,
|
74 | ...options
|
75 | })
|
76 | } catch (e) {
|
77 | if (e.timeout) {
|
78 | throw createTimeoutError('waitForValueToChange', options)
|
79 | }
|
80 | throw e
|
81 | }
|
82 | }
|
83 |
|
84 | return {
|
85 | wait,
|
86 | waitForNextUpdate,
|
87 | waitForValueToChange
|
88 | }
|
89 | }
|
90 |
|
91 | export default asyncUtils
|