18
Test Asynchronous Calls With the Jest
It's common in JavaScript for code to run asynchronously. When you have code that runs asynchronously, Jest needs to know when the code it is testing has completed, before it can move on to another test. Jest has several ways to handle this.
Asynchronous calls don’t block or wait for calls to return. After the call is made, program execution continues. When the call returns, a callback function is executed. It’s hard to test asynchronous calls due to the asynchronous nature.
The following is a unit test case for an asynchronous call
describe('test asynchronous call', () => { it('this should not pass', () => { setTimeout(() => { expect(1).toBe(2); }); }); });
Apparently, 1 isn’t 2, but the test passes.
setTimeout is called and returns. The test finishes before inside the setTimeout is executed. No error is found before the test exits — therefore, the test case passes.
We can fix this issue by waiting for setTimeout to finish.
describe('test asynchronous call', () => { it('this should not pass', done => { setTimeout(() => { expect(1).toBe(2); done(); }); }); });
We pass in Jest’s done callback to the test case and wait for setTimeout to finish. And then we invoke done() to tell Jest it can exit now. With the help of the done callback, this test case fails as expected.
If your code uses promises, there is simpler way to handle asynchronous tests. Return a promise from your test, and Jest will wait for that promise to resolve. If the promise is rejected, the test will automatically fail.
For example, let's say that fetchData returns a promise that is supposed to resolve to the string 'peanut butter'. We could test it with:
test('the data is peanut butter', () => { return fetchData().then((data) => { expect(data).toBe('peanut butter'); }); })
Be sure to return the promise - if you omit this return statement, your test will complete before fetchData completes.
We have explored the main asynchronous patterns on JavaScript and the ways to test them with Jest.