@@ -292,12 +292,11 @@ test('the real timers => fake timers error shows the original stack trace when c
292292
293293test ( 'does not work after it resolves' , async ( ) => {
294294 jest . useFakeTimers ( 'modern' )
295- let context = 'initial'
295+ const contextStack = [ ]
296296 configure ( {
297297 // @testing -library/react usage to ensure `IS_REACT_ACT_ENVIRONMENT` is set when acting.
298298 unstable_advanceTimersWrapper : callback => {
299- const originalContext = context
300- context = 'act'
299+ contextStack . push ( 'act:start' )
301300 try {
302301 const result = callback ( )
303302 // eslint-disable-next-line jest/no-if, jest/no-conditional-in-test -- false-positive
@@ -307,54 +306,144 @@ test('does not work after it resolves', async () => {
307306 then : ( resolve , reject ) => {
308307 thenable . then (
309308 returnValue => {
310- context = originalContext
309+ contextStack . push ( 'act:end' )
311310 resolve ( returnValue )
312311 } ,
313312 error => {
314- context = originalContext
313+ contextStack . push ( 'act:end' )
315314 reject ( error )
316315 } ,
317316 )
318317 } ,
319318 }
320319 } else {
321- context = originalContext
320+ contextStack . push ( 'act:end' )
322321 return undefined
323322 }
324323 } catch {
325- context = originalContext
324+ contextStack . push ( 'act:end' )
326325 return undefined
327326 }
328327 } ,
329328 asyncWrapper : async callback => {
330- const originalContext = context
331- context = 'no-act'
329+ contextStack . push ( 'no-act:start' )
332330 try {
333331 await callback ( )
334332 } finally {
335- context = originalContext
333+ contextStack . push ( 'no-act:end' )
336334 }
337335 } ,
338336 } )
339337
340- let data = null
338+ let timeoutResolved = false
341339 setTimeout ( ( ) => {
342- data = 'resolved'
340+ contextStack . push ( 'timeout' )
341+ timeoutResolved = true
343342 } , 100 )
344343
344+ contextStack . push ( 'waitFor:start' )
345345 await waitFor (
346346 ( ) => {
347+ contextStack . push ( 'callback' )
347348 // eslint-disable-next-line jest/no-conditional-in-test -- false-positive
348- if ( data === null ) {
349+ if ( ! timeoutResolved ) {
349350 throw new Error ( 'not found' )
350351 }
351352 } ,
352353 { interval : 50 } ,
353354 )
354-
355- expect ( context ) . toEqual ( 'initial' )
355+ contextStack . push ( 'waitFor:end' )
356+
357+ expect ( contextStack ) . toMatchInlineSnapshot ( `
358+ [
359+ waitFor:start,
360+ no-act:start,
361+ callback,
362+ act:start,
363+ act:end,
364+ callback,
365+ act:start,
366+ timeout,
367+ act:end,
368+ callback,
369+ no-act:end,
370+ waitFor:end,
371+ ]
372+ ` )
356373
357374 await Promise . resolve ( )
358375
359- expect ( context ) . toEqual ( 'initial' )
376+ // The context call stack should not change
377+ expect ( contextStack ) . toMatchInlineSnapshot ( `
378+ [
379+ waitFor:start,
380+ no-act:start,
381+ callback,
382+ act:start,
383+ act:end,
384+ callback,
385+ act:start,
386+ timeout,
387+ act:end,
388+ callback,
389+ no-act:end,
390+ waitFor:end,
391+ ]
392+ ` )
393+ } )
394+
395+ test ( `when fake timer is installed, on waitFor timeout, it doesn't call the callback afterward` , async ( ) => {
396+ jest . useFakeTimers ( 'modern' )
397+
398+ configure ( {
399+ // @testing -library/react usage to ensure `IS_REACT_ACT_ENVIRONMENT` is set when acting.
400+ unstable_advanceTimersWrapper : callback => {
401+ try {
402+ const result = callback ( )
403+ // eslint-disable-next-line jest/no-if, jest/no-conditional-in-test -- false-positive
404+ if ( typeof result ?. then === 'function' ) {
405+ const thenable = result
406+ return {
407+ then : ( resolve , reject ) => {
408+ thenable . then (
409+ returnValue => {
410+ resolve ( returnValue )
411+ } ,
412+ error => {
413+ reject ( error )
414+ } ,
415+ )
416+ } ,
417+ }
418+ } else {
419+ return undefined
420+ }
421+ } catch {
422+ return undefined
423+ }
424+ } ,
425+ asyncWrapper : async callback => {
426+ try {
427+ await callback ( )
428+ } finally {
429+ /* eslint no-empty: "off" */
430+ }
431+ } ,
432+ } )
433+
434+ const callback = jest . fn ( ( ) => {
435+ throw new Error ( 'We want to timeout' )
436+ } )
437+ const interval = 50
438+
439+ await expect ( ( ) =>
440+ waitFor ( callback , { interval, timeout : 100 } ) ,
441+ ) . rejects . toThrow ( )
442+ expect ( callback ) . toHaveBeenCalledWith ( )
443+
444+ callback . mockClear ( )
445+
446+ await jest . advanceTimersByTimeAsync ( interval )
447+
448+ expect ( callback ) . not . toHaveBeenCalledWith ( )
360449} )
0 commit comments