fake-timers: Problem with useFakeTimers: Promise are freeze when resolve it from setTimeout
From @Qoter on May 5, 2017 13:30
- Sinon version : 2.2.0
- Environment : Node.js v6.10.2
- Other libraries: mocha 3.3.0
Code example
it('promise freeze', () => {
let clock = sinon.useFakeTimers();
let p = Promise.resolve()
.then(() => new Promise(resolve => setTimeout(resolve, 5)));
clock.tick(1000);
return p;
});
I expect that test will pass.
But test fail with timeout and promise are frozen.
Without sinon.useFakeTimers() this test will pass.
Copied from original issue: sinonjs/sinon#1397
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 19 (15 by maintainers)
This is expected behaviour and how promises behave.
The
clock.tickwill execute before thesetTimeoutcall because promises always defer a microtask. That’s the issue - the reason the test “succeeds” without lolex is that 5ms actually pass and the test is async.There is nothing we can do about this at this point. On the other hand I’ve been talking with the V8 team about exposing a flag (they already have) that lets you flush the promise microtick queue which would be great - they’re working on it 😃
@rgomezp I just tried manually seeing if it was there. I grepped for
tick,promise,flushby doingnode --v8-options | grep flush, and I could not see anything that related to it. So it does not seem to be there.I am quite sure you are able to find the Node developers mailing list or similar if you search for it, but not sure that is the quickest route to your goal. If you want easier testing, you could consider using a promise library in between, which is how guess Angular’s flushMicrotasks achieves this.
Thank @fatso83 for moving this. And many thanks to you @benjamingr, for explaining exactly what is going on.
Thanks, benji. Didn’t use much time looking into the specifics, just saw it lingering on the main Sinon project and thought it should be moved here.
From @lucasfcosta on May 6, 2017 18:38
Hi @Qoter, thanks for your issue 😄
I believe this happens because you either gotta use a timer from the
clockvariable you assigneduseFakeTimersto or you need to call theinstallmethod.This is one of the possible fixes for your test:
The other one, using
installto replace the globalsetTimeoutfunction can be used by installing thelolexmodule, as you can see in this section at Lolex docs.