I am trying to understand the difference between clock.tick
and clock.tickAsync
and where should I use each one. The explanation in the docs is not clear to me, and by looking at the code itself I still can't understand where and when should I use each method. Can anyone help me with a concrete code example?
The tickAsync() will also break the event loop, allowing any scheduled promise callbacks to execute before running the timers.
First, I recommend looking the video about event loop.
If short, the difference between tick
and tickAsync
is that tick
- is call timers synchronous and tickAsync
is - call timers asynchronous that allow to execute resolved promises before calling timers
What synchronous means. Let's look at the example code which we would test
function myFunction() {
setTimeout(() => console.log('foo'), 1000)
Promise.resolve().then(() => console.log('zoo'));
console.log('bar')
}
and our synchronous test code
it('should test synchronously', () => {
myFunction()
tick(1000); // This would call scheduled timers synchronously ⚠️
console.log('baz')
});
// print 'bar'
// print 'foo'
// print 'baz'
// print 'zoo'
and now let's see the same test code but with tickAsync
it('should test synchronously', () => {
myFunction()
tickAsync(1000);
console.log('baz')
});
// print 'bar'
// print 'baz' 👈
// print 'zoo' 👈
// print 'foo' 👈
As you can see, the order of printed string is changed.
Now the same code but with await
it('should test synchronously', async () => {
myFunction()
await tickAsync(1000);
console.log('baz')
});
// print 'bar'
// print 'zoo' 👈
// print 'foo' 👈
// print 'baz' 👈
To understand why the order changed, you should understand the difference betweens micro tasks queue and regular queue. But if you watched the video from link above, you already should get the idea 😊
P.S.
Also, you should understand that sinon.useFakeTimers();
will replace setTimeout
and setInterval
on own implementation that allow sinon to have full control over your timers passed to these functions
This is a very rough approximation how sinon tick
& tickAsync
implemented
scheduledTimers = [];
function useFakeTimers() {
global.setInterval = global.setTimeout = (fn) => {
scheduledTimers.push(fn);
}
}
function tick() {
while (scheduledTimers.length) {
scheduledTimers.shift()();
}
}
function tickAsync() {
// Call timers on the next tick
return Promise.resolve().then(() => tick());
}