Jest fake timers with promises
Since [email protected]
you can choose between two different fake timer implementations.
I found that jest.useFakeTimers('legacy')
works with Promises using the flushPromises
workaround, but it doesn't work with Date
, whereas jest.useFakeTimers('modern')
works with Date
but not with Promises since await flushPromises()
never resolves.
The best solution I found was to use @sinonjs/fake-timers
instead, since that one works with both Promises and Date
without any sort of workarounds or hacks:
import FakeTimers from "@sinonjs/fake-timers";
// Before tests:
const clock = FakeTimers.install();
// In tests:
await clock.tickAsync(100);
// After tests:
clock.uninstall();
The current best alternative is to use the async versions of fake-timers. So you would do
await clock.tickAsync(1000); // doesn't wait 1000ms but is async
Instead of calling clock.tick
. Please see the answer below for more details.
At the moment, it's not supported
You're not doing anything wrong - it doesn't work at the moment - sorry. The following things have to happen before this will work from our end:
- Jest needs to merge the ongoing work to merge lolex as their fake timer implementation here https://github.com/facebook/jest/pull/5171
- Lolex needs to support pumping through promises - we've discussed this with the V8 team in a recent Node.js collaborator summit. That would expose a hook we'll use to allow doing something like
advanceTimeByTime(100)
and have that work with promises.
The problem in a gist is that the .then(spy)
only gets called later.
As we are volunteers - there is no concrete timeline for these things. I hope SimenB does the merge in the coming 2-3 months and I'll follow up with the hook with the V8 team next month.
What you can do now
You can always write an async test:
// note this is an async function now
it('resolves in a given amount of time', async () => {
// this is in a promise.reoslve.then to not 'lock' on the await
Promise.resolve().then(() => jest.advanceTimersByTime(100));
await timeout(100);
});
You can add expectations after the timeout if there is anything else you want to wait for.