在我们撰写jest的时候,常常会遇到source code的function有使用到setTimeout的情况,若是我们在jest中也使用setTimeout来模拟source code的真实timeout情况,那麽一旦jest的数量变多时就会花费很多时间在等待timeout,所以jest就提供了fakeTimers
的功能,他可以让使用者透过这个function达到自由控制时间(timer时间)的功能。
// timerGame.js
'use strict';
function timerGame(callback) {
console.log('Ready....go!');
setTimeout(() => {
console.log("Time's up -- stop!");
callback && callback();
}, 1000);
}
module.exports = timerGame;
// __tests__/timerGame-test.js
'use strict';
jest.useFakeTimers();
test('waits 1 second before ending the game', () => {
const timerGame = require('../timerGame');
timerGame();
expect(setTimeout).toHaveBeenCalledTimes(1);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 1000);
});
使用jest.useFakeTimers()
来开启fake timers功能,他模拟了setTimeout或其他timer的功能,若是在同一个jest中使用了多个fake timers则需要在beforeEach中再次设定jest.useFakeTimers(),否则timer不会重置。
test('calls the callback after 1 second', () => {
const timerGame = require('../timerGame');
const callback = jest.fn();
timerGame(callback);
// At this point in time, the callback should not have been called yet
expect(callback).not.toBeCalled();
// Fast-forward until all timers have been executed
jest.runAllTimers();
// Now our callback should have been called!
expect(callback).toBeCalled();
expect(callback).toHaveBeenCalledTimes(1);
});
以上面的例子来说,若我们需要若我们需要在一秒後呼叫这个callback function,所以我们使用jest的API(jest.runAllTimers())来加快timer的时间。
在还没使用jest.runAllTimers()
时,callback function因为还在处於setTimeout阶段所以还没被执行,而当执行了jest的API那他就会将所有timer加快让他提前完成,所以下一行就可以看到callback function已经提前被呼叫了,这就是jest fake timer的功能。
若你是使用resursive timer
,因为他是在callback function中再设定一个timer,所以并不适合使用jest.runAllTimers()
,这种情况可以使用jest.runOnlyPendingTimers()
。
// infiniteTimerGame.js
'use strict';
function infiniteTimerGame(callback) {
console.log('Ready....go!');
setTimeout(() => {
console.log("Time's up! 10 seconds before the next game starts...");
callback && callback();
// Schedule the next game in 10 seconds
setTimeout(() => {
infiniteTimerGame(callback);
}, 10000);
}, 1000);
}
module.exports = infiniteTimerGame;
// __tests__/infiniteTimerGame-test.js
'use strict';
jest.useFakeTimers();
describe('infiniteTimerGame', () => {
test('schedules a 10-second timer after 1 second', () => {
const infiniteTimerGame = require('../infiniteTimerGame');
const callback = jest.fn();
infiniteTimerGame(callback);
/* At this point in time, there should have been a single call to
setTimeout to schedule the end of the game in 1 second. */
expect(setTimeout).toHaveBeenCalledTimes(1);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 1000);
/* Fast forward and exhaust only currently pending timers
(but not any new timers that get created during that process) */
jest.runOnlyPendingTimers();
// At this point, our 1-second timer should have fired it's callback
expect(callback).toBeCalled();
/* And it should have created a new timer to start the game over in
10 seconds */
expect(setTimeout).toHaveBeenCalledTimes(2);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 10000);
});
});
由於source code中的function递回的呼叫自身,并在自身中在建立一个setTimeout,所以我们在jest中呼叫这个function
jest.runOnluPendingTimers()
将这个一秒的timeout加速。我们也可以使用jest.advanceTimersByTime(msToRun)
来指定需要加速多少毫秒。
// timerGame.js
'use strict';
function timerGame(callback) {
console.log('Ready....go!');
setTimeout(() => {
console.log("Time's up -- stop!");
callback && callback();
}, 1000);
}
module.exports = timerGame;
it('calls the callback after 1 second via advanceTimersByTime', () => {
const timerGame = require('../timerGame');
const callback = jest.fn();
timerGame(callback);
// At this point in time, the callback should not have been called yet
expect(callback).not.toBeCalled();
// Fast-forward 1000ms
jest.advanceTimersByTime(1000);
// Now our callback should have been called!
expect(callback).toBeCalled();
expect(callback).toHaveBeenCalledTimes(1);
});
由於我们的source code中的timer设定为等待1秒,所以们可以指定将timer加速1s。
在某些时候我们会需要在测试结束後清除所有的timers,所以jest也提供了jest.clearAllTimers()
的API。
参考文献:
jest timer-mocks
<<: 企业专有资料进行分类的最佳角色- 资料管家(Data Steward)
>>: 《赖田捕手:番外篇》第 40 天:用 Netlify 整合前後端服务
先来看看 MDN 的定义。 回呼函式(callback function)是指能藉由 argumen...
过去的我,一提到 GitHub Action 就直接联想到持续整合与布署,然後就开始进入如何设计、撰...
昨日完成了爬虫功能开发,今天会将此功能打包成一个套件,并使用pip安装到虚拟环境上。 套件架构 要让...
电脑维修常见问题 一、电脑问题如何检查? 电脑故障或电脑维修问题可以分为二大类:软件或硬件。 软件故...
Alias Records 一种 record 类型, 让你将流量路由到 AWS resource...