1
+ import { useState , useRef , useEffect } from 'react'
2
+
1
3
describe ( 'async hook (fake timers) tests' , ( ) => {
4
+ const useSequence = ( values : string [ ] , intervalMs = 50 ) => {
5
+ const [ first , ...otherValues ] = values
6
+ const [ value , setValue ] = useState ( ( ) => first )
7
+ const index = useRef ( 0 )
8
+
9
+ useEffect ( ( ) => {
10
+ const interval = setInterval ( ( ) => {
11
+ setValue ( otherValues [ index . current ++ ] )
12
+ if ( index . current >= otherValues . length ) {
13
+ clearInterval ( interval )
14
+ }
15
+ } , intervalMs )
16
+ return ( ) => {
17
+ clearInterval ( interval )
18
+ }
19
+ // eslint-disable-next-line react-hooks/exhaustive-deps
20
+ } , otherValues )
21
+
22
+ return value
23
+ }
24
+
2
25
beforeEach ( ( ) => {
3
26
jest . useFakeTimers ( )
4
27
} )
@@ -70,7 +93,7 @@ describe('async hook (fake timers) tests', () => {
70
93
71
94
setTimeout ( ( ) => {
72
95
actual = expected
73
- } , 101 )
96
+ } , 30 )
74
97
75
98
let complete = false
76
99
@@ -80,14 +103,243 @@ describe('async hook (fake timers) tests', () => {
80
103
expect ( actual ) . toBe ( expected )
81
104
complete = true
82
105
} ,
83
- { timeout : 100 , interval : 50 }
106
+ { timeout : 29 , interval : 10 }
84
107
)
85
- ) . rejects . toThrow ( Error ( 'Timed out in waitFor after 100ms .' ) )
108
+ ) . rejects . toThrow ( Error ( 'Timed out in waitFor after 29ms .' ) )
86
109
87
110
expect ( complete ) . toBe ( false )
88
111
} )
112
+
113
+ test ( 'should wait for next update' , async ( ) => {
114
+ const { result, waitForNextUpdate } = renderHook ( ( ) => useSequence ( [ 'first' , 'second' ] ) )
115
+
116
+ expect ( result . current ) . toBe ( 'first' )
117
+
118
+ await waitForNextUpdate ( )
119
+
120
+ expect ( result . current ) . toBe ( 'second' )
121
+ } )
122
+
123
+ test ( 'should wait for multiple updates' , async ( ) => {
124
+ const { result, waitForNextUpdate } = renderHook ( ( ) =>
125
+ useSequence ( [ 'first' , 'second' , 'third' ] )
126
+ )
127
+
128
+ expect ( result . current ) . toBe ( 'first' )
129
+
130
+ await waitForNextUpdate ( )
131
+
132
+ expect ( result . current ) . toBe ( 'second' )
133
+
134
+ await waitForNextUpdate ( )
135
+
136
+ expect ( result . current ) . toBe ( 'third' )
137
+ } )
138
+
139
+ test ( 'should reject if timeout exceeded when waiting for next update' , async ( ) => {
140
+ const { result, waitForNextUpdate } = renderHook ( ( ) => useSequence ( [ 'first' , 'second' ] ) )
141
+
142
+ expect ( result . current ) . toBe ( 'first' )
143
+
144
+ await expect ( waitForNextUpdate ( { timeout : 10 } ) ) . rejects . toThrow (
145
+ Error ( 'Timed out in waitForNextUpdate after 10ms.' )
146
+ )
147
+ } )
148
+
149
+ test ( 'should not reject when waiting for next update if timeout has been disabled' , async ( ) => {
150
+ const { result, waitForNextUpdate } = renderHook ( ( ) => useSequence ( [ 'first' , 'second' ] , 1100 ) )
151
+
152
+ expect ( result . current ) . toBe ( 'first' )
153
+
154
+ await waitForNextUpdate ( { timeout : false } )
155
+
156
+ expect ( result . current ) . toBe ( 'second' )
157
+ } )
158
+
159
+ test ( 'should wait for expectation to pass' , async ( ) => {
160
+ const { result, waitFor } = renderHook ( ( ) => useSequence ( [ 'first' , 'second' , 'third' ] ) )
161
+
162
+ expect ( result . current ) . toBe ( 'first' )
163
+
164
+ let complete = false
165
+ await waitFor ( ( ) => {
166
+ expect ( result . current ) . toBe ( 'third' )
167
+ complete = true
168
+ } )
169
+ expect ( complete ) . toBe ( true )
170
+ } )
171
+
172
+ test ( 'should wait for arbitrary expectation to pass' , async ( ) => {
173
+ const { waitFor } = renderHook ( ( ) => null )
174
+
175
+ let actual = 0
176
+ const expected = 1
177
+
178
+ setTimeout ( ( ) => {
179
+ actual = expected
180
+ } , 200 )
181
+
182
+ let complete = false
183
+ await waitFor ( ( ) => {
184
+ expect ( actual ) . toBe ( expected )
185
+ complete = true
186
+ } )
187
+
188
+ expect ( complete ) . toBe ( true )
189
+ } )
190
+
191
+ test ( 'should not hang if expectation is already passing' , async ( ) => {
192
+ const { result, waitFor } = renderHook ( ( ) => useSequence ( [ 'first' , 'second' ] ) )
193
+
194
+ expect ( result . current ) . toBe ( 'first' )
195
+
196
+ let complete = false
197
+ await waitFor ( ( ) => {
198
+ expect ( result . current ) . toBe ( 'first' )
199
+ complete = true
200
+ } )
201
+ expect ( complete ) . toBe ( true )
202
+ } )
203
+
204
+ test ( 'should wait for truthy value' , async ( ) => {
205
+ const { result, waitFor } = renderHook ( ( ) => useSequence ( [ 'first' , 'second' , 'third' ] ) )
206
+
207
+ expect ( result . current ) . toBe ( 'first' )
208
+
209
+ await waitFor ( ( ) => result . current === 'third' )
210
+
211
+ expect ( result . current ) . toBe ( 'third' )
212
+ } )
213
+
214
+ test ( 'should wait for arbitrary truthy value' , async ( ) => {
215
+ const { waitFor } = renderHook ( ( ) => null )
216
+
217
+ let actual = 0
218
+ const expected = 1
219
+
220
+ setTimeout ( ( ) => {
221
+ actual = expected
222
+ } , 200 )
223
+
224
+ await waitFor ( ( ) => actual === 1 )
225
+
226
+ expect ( actual ) . toBe ( expected )
227
+ } )
228
+
229
+ test ( 'should reject if timeout exceeded when waiting for expectation to pass' , async ( ) => {
230
+ const { result, waitFor } = renderHook ( ( ) => useSequence ( [ 'first' , 'second' , 'third' ] ) )
231
+
232
+ expect ( result . current ) . toBe ( 'first' )
233
+
234
+ await expect (
235
+ waitFor (
236
+ ( ) => {
237
+ expect ( result . current ) . toBe ( 'third' )
238
+ } ,
239
+ { timeout : 75 }
240
+ )
241
+ ) . rejects . toThrow ( Error ( 'Timed out in waitFor after 75ms.' ) )
242
+ } )
243
+
244
+ test ( 'should not reject when waiting for expectation to pass if timeout has been disabled' , async ( ) => {
245
+ const { result, waitFor } = renderHook ( ( ) => useSequence ( [ 'first' , 'second' , 'third' ] , 550 ) )
246
+
247
+ expect ( result . current ) . toBe ( 'first' )
248
+
249
+ await waitFor (
250
+ ( ) => {
251
+ expect ( result . current ) . toBe ( 'third' )
252
+ } ,
253
+ { timeout : false }
254
+ )
255
+
256
+ expect ( result . current ) . toBe ( 'third' )
257
+ } )
258
+
259
+ test ( 'should check on interval when waiting for expectation to pass' , async ( ) => {
260
+ const { result, waitFor } = renderHook ( ( ) => useSequence ( [ 'first' , 'second' , 'third' ] ) )
261
+
262
+ let checks = 0
263
+
264
+ await waitFor (
265
+ ( ) => {
266
+ checks ++
267
+ return result . current === 'third'
268
+ } ,
269
+ { interval : 100 }
270
+ )
271
+
272
+ expect ( checks ) . toBe ( 3 )
273
+ } )
274
+
275
+ test ( 'should wait for value to change' , async ( ) => {
276
+ const { result, waitForValueToChange } = renderHook ( ( ) =>
277
+ useSequence ( [ 'first' , 'second' , 'third' ] )
278
+ )
279
+
280
+ expect ( result . current ) . toBe ( 'first' )
281
+
282
+ await waitForValueToChange ( ( ) => result . current === 'third' )
283
+
284
+ expect ( result . current ) . toBe ( 'third' )
285
+ } )
286
+
287
+ test ( 'should wait for arbitrary value to change' , async ( ) => {
288
+ const { waitForValueToChange } = renderHook ( ( ) => null )
289
+
290
+ let actual = 0
291
+ const expected = 1
292
+
293
+ setTimeout ( ( ) => {
294
+ actual = expected
295
+ } , 200 )
296
+
297
+ await waitForValueToChange ( ( ) => actual )
298
+
299
+ expect ( actual ) . toBe ( expected )
300
+ } )
301
+
302
+ test ( 'should reject if timeout exceeded when waiting for value to change' , async ( ) => {
303
+ const { result, waitForValueToChange } = renderHook ( ( ) =>
304
+ useSequence ( [ 'first' , 'second' , 'third' ] )
305
+ )
306
+
307
+ expect ( result . current ) . toBe ( 'first' )
308
+
309
+ await expect (
310
+ waitForValueToChange ( ( ) => result . current === 'third' , {
311
+ timeout : 75
312
+ } )
313
+ ) . rejects . toThrow ( Error ( 'Timed out in waitForValueToChange after 75ms.' ) )
314
+ } )
315
+
316
+ test ( 'should not reject when waiting for value to change if timeout is disabled' , async ( ) => {
317
+ const { result, waitForValueToChange } = renderHook ( ( ) =>
318
+ useSequence ( [ 'first' , 'second' , 'third' ] , 550 )
319
+ )
320
+
321
+ expect ( result . current ) . toBe ( 'first' )
322
+
323
+ await waitForValueToChange ( ( ) => result . current === 'third' , {
324
+ timeout : false
325
+ } )
326
+
327
+ expect ( result . current ) . toBe ( 'third' )
328
+ } )
329
+
330
+ test ( 'should reject if selector throws error' , async ( ) => {
331
+ const { result, waitForValueToChange } = renderHook ( ( ) => useSequence ( [ 'first' , 'second' ] ) )
332
+
333
+ expect ( result . current ) . toBe ( 'first' )
334
+
335
+ await expect (
336
+ waitForValueToChange ( ( ) => {
337
+ if ( result . current === 'second' ) {
338
+ throw new Error ( 'Something Unexpected' )
339
+ }
340
+ return result . current
341
+ } )
342
+ ) . rejects . toThrow ( Error ( 'Something Unexpected' ) )
343
+ } )
89
344
} )
90
345
} )
91
-
92
- // eslint-disable-next-line jest/no-export
93
- export { }
0 commit comments