Skip to content

Commit 72880f8

Browse files
committed
Added waitForValueToChange async util with documentation
1 parent 9aca667 commit 72880f8

File tree

3 files changed

+81
-4
lines changed

3 files changed

+81
-4
lines changed

docs/api-reference.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,10 @@ function wait(callback: function(): boolean|void, options?: WaitOptions): Promis
110110
```
111111

112112
Returns a `Promise` that resolves if the provided callback executes without exception and returns a
113-
truthy or `undefined` value. The callback is tested after each render of the hook.
113+
truthy or `undefined` value. It is safe to use the [`result` of `renderHook`](/reference/api#result)
114+
in the callback to perform assertion or to test values.
114115

115-
It is safe to use the [`result` of `renderHook`](/reference/api#result) in the callback to perform
116-
assertion or to test values.
116+
The callback is tested after each render of the hook.
117117

118118
See the [`wait` Options](/reference/api#wait-options) section for more details on the optional
119119
`options` parameter.
@@ -130,6 +130,21 @@ the result of an asynchronous update.
130130
See the [`wait` Options](/reference/api#wait-options) section for more details on the optional
131131
`options` parameter.
132132

133+
### `waitForValueToChange`
134+
135+
```js
136+
function waitForValueToChange(selector: function(): any, options?: WaitOptions): Promise<void>
137+
```
138+
139+
Returns a `Promise` that resolves if the value returned from the provided selector changes. It
140+
expected that the [`result` of `renderHook`](/reference/api#result) to select the value for
141+
comparison.
142+
143+
The value is selected for comparison after each render of the hook.
144+
145+
See the [`wait` Options](/reference/api#wait-options) section for more details on the optional
146+
`options` parameter.
147+
133148
### `wait` Options
134149

135150
The async utilities accepts the following options:

src/asyncUtils.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,30 @@ function asyncUtils(addResolver) {
5959
}
6060
}
6161

62+
const waitForValueToChange = async (selector, options = {}) => {
63+
const initialTimeout = options.timeout
64+
const initialValue = actForResult(selector)
65+
while (true) {
66+
const startTime = Date.now()
67+
try {
68+
await waitForNextUpdate(options)
69+
if (actForResult(selector) !== initialValue) {
70+
break
71+
}
72+
} catch (e) {
73+
if (e.timeout) {
74+
throw createTimeoutError('waitForValueToChange', initialTimeout)
75+
}
76+
throw e
77+
}
78+
options.timeout -= Date.now() - startTime
79+
}
80+
}
81+
6282
return {
6383
wait,
64-
waitForNextUpdate
84+
waitForNextUpdate,
85+
waitForValueToChange
6586
}
6687
}
6788

test/asyncHook.test.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,45 @@ describe('async hook tests', () => {
101101
)
102102
).rejects.toThrow(Error('Timed out in wait after 75ms.'))
103103
})
104+
105+
test('should wait for value to change', async () => {
106+
const { result, waitForValueToChange } = renderHook(() =>
107+
useSequence('first', 'second', 'third')
108+
)
109+
110+
expect(result.current).toBe('first')
111+
112+
await waitForValueToChange(() => result.current === 'third')
113+
114+
expect(result.current).toBe('third')
115+
})
116+
117+
test('should reject if timeout exceeded when waiting for value to change', async () => {
118+
const { result, waitForValueToChange } = renderHook(() =>
119+
useSequence('first', 'second', 'third')
120+
)
121+
122+
expect(result.current).toBe('first')
123+
124+
await expect(
125+
waitForValueToChange(() => result.current === 'third', {
126+
timeout: 75
127+
})
128+
).rejects.toThrow(Error('Timed out in waitForValueToChange after 75ms.'))
129+
})
130+
131+
test('should reject if selector throws error', async () => {
132+
const { result, waitForValueToChange } = renderHook(() => useSequence('first', 'second'))
133+
134+
expect(result.current).toBe('first')
135+
136+
await expect(
137+
waitForValueToChange(() => {
138+
if (result.current === 'second') {
139+
throw new Error('Something Unexpected')
140+
}
141+
return result.current
142+
})
143+
).rejects.toThrow(Error('Something Unexpected'))
144+
})
104145
})

0 commit comments

Comments
 (0)