1+ import { useState , useRef , useEffect } from 'react'
2+
13describe ( '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+
225 beforeEach ( ( ) => {
326 jest . useFakeTimers ( )
427 } )
@@ -70,7 +93,7 @@ describe('async hook (fake timers) tests', () => {
7093
7194 setTimeout ( ( ) => {
7295 actual = expected
73- } , 101 )
96+ } , 30 )
7497
7598 let complete = false
7699
@@ -80,14 +103,243 @@ describe('async hook (fake timers) tests', () => {
80103 expect ( actual ) . toBe ( expected )
81104 complete = true
82105 } ,
83- { timeout : 100 , interval : 50 }
106+ { timeout : 29 , interval : 10 }
84107 )
85- ) . rejects . toThrow ( Error ( 'Timed out in waitFor after 100ms .' ) )
108+ ) . rejects . toThrow ( Error ( 'Timed out in waitFor after 29ms .' ) )
86109
87110 expect ( complete ) . toBe ( false )
88111 } )
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+ } )
89344 } )
90345} )
91-
92- // eslint-disable-next-line jest/no-export
93- export { }
0 commit comments