useFakeTimers breaks with native promise implementation
See original GitHub issue🐛 Bug Report
Use the native Promise implementation breaks useFakeTimers
To Reproduce
Steps to reproduce the behavior:
jest.useFakeTimers();
test('timing', () => {
Promise.resolve().then(() => console.log('promise'));
setTimeout(() => console.log('timer'), 100);
jest.runAllTimers();
console.log('end');
});
Expected behavior
It should log:
- promise
- timer
- end
This is because runAllTimers
should trigger the async promise handler first, then the timeout delayed by 100ms, then return control.
Actual Behaviour
- timer
- end
- promise
Link to repl or repo (highly encouraged)
Issue Analytics
- State:
- Created 5 years ago
- Reactions:34
- Comments:20 (6 by maintainers)
Top Results From Across the Web
Jest fake timers with promises - Stack Overflow
I found that jest.useFakeTimers('legacy') works with Promises using the flushPromises workaround, but it doesn't work with Date , whereas jest.
Read more >Jest 27: New Defaults for Jest, 2021 edition
We introduced a few more small breaking changes to help you avoid mistakes by disallowing some things that can easily happen unintentionally:.
Read more >Testing Recipes - React
However, these testing strategies don't depend on implementation details, ... Use the asynchronous version of act to apply resolved promises await act(async ...
Read more >Promise.race() - JavaScript - MDN Web Docs
The Promise.race() method takes an iterable of promises as input and ... how Promise.race() can be used to race several timers implemented ......
Read more >Jest で Promise + setTimeout のテストがつまる件 - Qiita
Jest で Promise の返り値のテストを書いていたときに setTimeout が絡むと非同期の ... useFakeTimers breaks with native promise implementation
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I would like to expand on this issue since it gets amplified by uses of setTimeouts within the async code:
Timeout - Async callback was not invoked within the 30000ms timeout specified by jest.setTimeout.
Expected: before-promise -> after-promise -> timer -> end Actual: timer -> before-promise -> Hangs
This issue here is there is nothing to continuously advance the timers once you’re within the promise world. shouldResolve will never resolve.
Switching to
global.Promise = require('promise');
does seem like does the trick to resolve the issue for this particular use case. However in practice we have found the it does not work for all use-cases.The best solution without replacing promises that i have come up for this is a utility function to continuouslyAdvanceTimers. However your results will still be out of order.
Expected: before-promise -> after-promise -> timer -> end Actual: timer -> before-promise -> after-promise -> end
Posting this work around in case it helps someone else:
await Promise.resolve().then(() => jest.advanceTimersByTime(milliseconds));
More context here: https://stackoverflow.com/questions/51126786/jest-fake-timers-with-promises/51132058#51132058
Broader example: