How do I test promise delays with jest?
promiseDelay
returns a Promise
that resolves after ms
so call a spy
in then
and test to see if the spy
has been called after different intervals:
describe('promiseDelay', () => {
beforeEach(() => { jest.useFakeTimers(); });
afterEach(() => { jest.useRealTimers(); });
test('should not resolve until timeout has elapsed', async () => {
const spy = jest.fn();
promiseDelay(100).then(spy); // <= resolve after 100ms
jest.advanceTimersByTime(20); // <= advance less than 100ms
await Promise.resolve(); // let any pending callbacks in PromiseJobs run
expect(spy).not.toHaveBeenCalled(); // SUCCESS
jest.advanceTimersByTime(80); // <= advance the rest of the time
await Promise.resolve(); // let any pending callbacks in PromiseJobs run
expect(spy).toHaveBeenCalled(); // SUCCESS
});
});
Note that test code is synchronous and Timer Mocks make setTimeout
synchronous but then
queues a callback in PromiseJobs
so any queued callbacks need to be allowed to run before testing if the spy
has been called.
This can be done by using an async
test function and calling await
on a resolved Promise
which effectively queues the rest of the test at the end of PromiseJobs
allowing any pending callbacks to run before the test continues.
Additional information about how promises and fake timers interact is available in my answer here.
Comments
-
Ajay Kumar Ganesh almost 2 years
Here's my code which I use to delay process (for backoff)
export function promiseDelay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
I would want to test it but I'm not able to. I tried working with fakeTimers but my test never ends.
test('promiseDelay delays for 1s', async (done) => { jest.useFakeTimers(); Promise.resolve().then(() => jest.advanceTimersByTime(100)); await promiseDelay(100); });
-
Brian Adams over 5 years@thegeekajay The test in the question provides the argument
done
to the test function but never calls it, that's the reason that particular test never finishes: "Jest will also wait if you provide an argument to the test function, usually called done" -
Ajay Kumar Ganesh over 5 yearsThanks, i figured that out and fixed it. but the test 'should not resolve if < 100ms' is always failing. coz the spy function was called.
-
Asking over 2 years@BrianAdams, why the test does not work without
await Promise.resolve();
?