Reputation: 1429
In my NodeJS app I've got the following heplers.ts
file with one method, wait
:
export const wait = async (ms: number) => {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
};
I'm currently writing a unit test to this file and this is what I have now:
import { setProcessEnv } from 'spec/helpers';
import { wait } from '../../util/helpers';
describe('Helper methods', () => {
beforeEach(() => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000;
setProcessEnv();
});
it('should wait a specified amount of time', async () => {
const TIMEOUT = 10000;
jasmine.clock().install(); // First install the clock
await wait(TIMEOUT);
jasmine.clock().tick(10000); // waits till 10000 milliseconds
expect(wait).toHaveBeenCalled();
jasmine.clock().uninstall(); // uninstall clock when done
});
});
But I'm constantly receiving
Error: Timeout - Async function did not complete within 20000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)
I've increased jasmine.DEFAULT_TIMEOUT_INTERVAL
to 20000 ms, but it still didn't work.
How such async functions could be tested?
I've found coupes examples, but they didn't work in my case: How to test a function which has a setTimeout with jasmine?
UPDATE
This is my latest version that doesn't throw an error, but the problem is that it doesn't cover return statement lines (return new Promise(...
):
it('should wait a specified amount of time', async () => {
const TIMEOUT = 10000;
// jasmine.clock().install(); // First install the clock
const wait = jasmine.createSpy();
await wait(TIMEOUT);
// jasmine.clock().tick(1000); // waits till 10000 milliseconds
expect(wait).toHaveBeenCalled();
expect(wait).toHaveBeenCalledWith(TIMEOUT);
// jasmine.clock().uninstall(); // uninstall clock when done
});
Upvotes: 2
Views: 3617
Reputation: 24555
The problem is that by using jasmine's custom clock you need to manually call .tick()
to move the time forward. Since you immediately await the wait
call, the setTimeout
within wait
will not be reached. Thus, the promise never resolves, as you call .tick()
after awaiting the promise.
You can fix this by not immediately awaiting the the promise returned from wait
but instead assigning it to a variable and then moving the time ahead. Then, await the promise and check if wait
has been called:
describe('Helper methods', () => {
it('should wait a specified amount of time', async () => {
const TIMEOUT = 10000;
jasmine.clock().install(); // First install the clock
const waitPromise = wait(TIMEOUT);
jasmine.clock().tick(10000); // waits till 10000 milliseconds
await waitPromise; // now await the promise
expect(wait).toHaveBeenCalled();
jasmine.clock().uninstall(); // uninstall clock when done
});
});
Note that in the above code no spy has been set up on wait
, so .toHaveBeenCalled
will probably fail. Check this link if you need help setting up a spy on a function: https://stackoverflow.com/a/43532075/3761628
To answer the updated question: You've incorrectly set up the spy. You need to change it to something like:
import { setProcessEnv } from 'spec/helpers';
import * as WaitFunction from from '../../util/helpers';
...
it('should wait a specified amount of time', async () => {
const TIMEOUT = 10000;
const waitSpy = spyOn(WaitFunction, 'wait').and.callThrough();
await WaitFunction.wait(TIMEOUT);
expect(waitSpy).toHaveBeenCalled();
expect(waitSpy).toHaveBeenCalledWith(TIMEOUT);
});
Upvotes: 2