跳转到主要内容
版本:26.倍

Dubluri de timp

本机计时器函数(例如,setTimeout,setInterval,clearTimeout,clearInterval)不是理想的测试环境,因为他们依赖于实时时间流逝。Jest poate înlocui cronometrele cu funcţii care vă permit să controlaţi trecerea timpului。伟大的斯科特!

/ / timerGame.js
使用严格的 ;
函数 timerGame ( 回调 ) {
控制台 日志 ( “准备好了……走吧!” ) ;
setTimeout ( ( ) = > {
控制台 日志 ( “时间到了——停止!” ) ;
回调 & & 回调 ( ) ;
} , 1000 ) ;
}
模块 出口 = timerGame ;
/ / __tests__ / timerGame-test.js
使用严格的 ;
开玩笑 useFakeTimers ( ) ;
测试 ( “等待1秒结束游戏” , ( ) = > {
常量 timerGame = 需要 ( “. . / timerGame” ) ;
timerGame ( ) ;
预计 ( setTimeout ) toHaveBeenCalledTimes ( 1 ) ;
预计 ( setTimeout ) toHaveBeenLastCalledWith ( 预计 任何 ( 函数 ) , 1000 ) ;
} ) ;

这里我们通过调用来启用假计时器jest.useFakeTimers ();。这个函数用模拟函数模拟setTimeout和其他计时器函数。如果在一个文件或描述块中运行多个测试,jest.useFakeTimers ();可以在每次测试之前手动调用,或者使用诸如beforeEach。不这样做将导致内部使用计数器不被重置。

Rularea tuturor cronometrelor#

我们可能想要为这个模块编写的另一个测试是断言回调在1秒后被调用。为了做到这一点,我们将使用Jest的计时器控件api在测试中间快进时间:

测试 ( ' 1秒后调用回调' , ( ) = > {
常量 timerGame = 需要 ( “. . / timerGame” ) ;
常量 回调 = 开玩笑 fn ( ) ;
timerGame ( 回调 ) ;
//此时,回调函数还没有被调用
预计 ( 回调 ) toBeCalled ( ) ;
//快进直到所有计时器都被执行
开玩笑 runAllTimers ( ) ;
//现在我们的回调函数已经被调用了!
预计 ( 回调 ) toBeCalled ( ) ;
预计 ( 回调 ) toHaveBeenCalledTimes ( 1 ) ;
} ) ;

Rularea cronometrelor în așteptare#

还有一种情况是,您可能有一个递归计时器——这是一个在自己的回调中设置新计时器的计时器。对于这些,运行所有的计时器将是一个无尽的循环jest.runAllTimers ()是不可取的。Pentru aceste cazuri s-ar putea folesjest.runOnlyPendingTimers ():

/ / infiniteTimerGame.js
使用严格的 ;
函数 infiniteTimerGame ( 回调 ) {
控制台 日志 ( “准备好了……走吧!” ) ;
setTimeout ( ( ) = > {
控制台 日志 ( “时间到了!下一场比赛开始前10秒……” ) ;
回调 & & 回调 ( ) ;
//在10秒内安排下一场比赛
setTimeout ( ( ) = > {
infiniteTimerGame ( 回调 ) ;
} , 10000 ) ;
} , 1000 ) ;
}
模块 出口 = infiniteTimerGame ;
/ / __tests__ / infiniteTimerGame-test.js
使用严格的 ;
开玩笑 useFakeTimers ( ) ;
描述 ( “infiniteTimerGame” , ( ) = > {
测试 ( “1秒后设置10秒计时器” , ( ) = > {
常量 infiniteTimerGame = 需要 ( “. . / infiniteTimerGame” ) ;
常量 回调 = 开玩笑 fn ( ) ;
infiniteTimerGame ( 回调 ) ;
//此时此刻,应该有一个单独的呼叫
// setTimeout设置游戏在1秒内结束。
预计 ( setTimeout ) toHaveBeenCalledTimes ( 1 ) ;
预计 ( setTimeout ) toHaveBeenLastCalledWith ( 预计 任何 ( 函数 ) , 1000 ) ;
//快进和耗尽当前挂起的计时器
//(但不是在此过程中创建的任何新计时器)
开玩笑 runOnlyPendingTimers ( ) ;
//此时,我们的1秒计时器应该已经触发了它的回调函数
预计 ( 回调 ) toBeCalled ( ) ;
//它应该创建一个新的计时器来重新开始游戏
/ / 10秒
预计 ( setTimeout ) toHaveBeenCalledTimes ( 2 ) ;
预计 ( setTimeout ) toHaveBeenLastCalledWith ( 预计 任何 ( 函数 ) , 10000 ) ;
} ) ;
} ) ;

按时间提前计时器#

重命名的runTimersToTimeadvanceTimersByTime在开玩笑22.0.0#

另一种可能性是使用jest.advanceTimersByTime (msToRun)。当这个API被调用时,所有计时器都被msToRun毫秒。所有通过setTimeout()或setInterval()排队并在此时间段内执行的挂起的“宏任务”将被执行。此外,如果这些宏任务调度新的宏任务,这些宏任务将在相同的时间框架内执行,这些宏任务将被执行,直到队列中没有剩余的宏任务,这些宏任务应该在msToRun毫秒内运行。

/ / timerGame.js
使用严格的 ;
函数 timerGame ( 回调 ) {
控制台 日志 ( “准备好了……走吧!” ) ;
setTimeout ( ( ) = > {
控制台 日志 ( “时间到了——停止!” ) ;
回调 & & 回调 ( ) ;
} , 1000 ) ;
}
模块 出口 = timerGame ;
( ' 1秒后通过advanceTimersByTime调用回调' , ( ) = > {
常量 timerGame = 需要 ( “. . / timerGame” ) ;
常量 回调 = 开玩笑 fn ( ) ;
timerGame ( 回调 ) ;
//此时,回调函数还没有被调用
预计 ( 回调 ) toBeCalled ( ) ;
//快进直到所有计时器都被执行
开玩笑 advanceTimersByTime ( 1000 ) ;
//现在我们的回调函数已经被调用了!
预计 ( 回调 ) toBeCalled ( ) ;
预计 ( 回调 ) toHaveBeenCalledTimes ( 1 ) ;
} ) ;

最后,在某些测试中,能够清除所有挂起的计时器有时可能很有用。对于这个,我们有jest.clearAllTimers ()

此示例的代码可在以下网站获得例子/计时器