An Async Example

First, enable Babel support in Jest as documented in the Getting Started guide.

Let’s implement a module that fetches user data from an API and returns the user name.

user.js

  1. import request from './request';
  2. export function getUserName(userID) {
  3. return request(`/users/${userID}`).then(user => user.name);
  4. }

In the above implementation, we expect the request.js module to return a promise. We chain a call to then to receive the user name.

Now imagine an implementation of request.js that goes to the network and fetches some user data:

request.js

  1. const http = require('http');
  2. export default function request(url) {
  3. return new Promise(resolve => {
  4. // This is an example of an http request, for example to fetch
  5. // user data from an API.
  6. // This module is being mocked in __mocks__/request.js
  7. http.get({path: url}, response => {
  8. let data = '';
  9. response.on('data', _data => (data += _data));
  10. response.on('end', () => resolve(data));
  11. });
  12. });
  13. }

Because we don’t want to go to the network in our test, we are going to create a manual mock for our request.js module in the __mocks__ folder (the folder is case-sensitive, __MOCKS__ will not work). It could look something like this:

__mocks__/request.js

  1. const users = {
  2. 4: {name: 'Mark'},
  3. 5: {name: 'Paul'},
  4. };
  5. export default function request(url) {
  6. return new Promise((resolve, reject) => {
  7. const userID = parseInt(url.substr('/users/'.length), 10);
  8. process.nextTick(() =>
  9. users[userID]
  10. ? resolve(users[userID])
  11. : reject({
  12. error: `User with ${userID} not found.`,
  13. }),
  14. );
  15. });
  16. }

Now let’s write a test for our async functionality.

__tests__/user-test.js

  1. jest.mock('../request');
  2. import * as user from '../user';
  3. // The assertion for a promise must be returned.
  4. it('works with promises', () => {
  5. expect.assertions(1);
  6. return user.getUserName(4).then(data => expect(data).toBe('Mark'));
  7. });

We call jest.mock('../request') to tell Jest to use our manual mock. it expects the return value to be a Promise that is going to be resolved. You can chain as many Promises as you like and call expect at any time, as long as you return a Promise at the end.

.resolves

There is a less verbose way using resolves to unwrap the value of a fulfilled promise together with any other matcher. If the promise is rejected, the assertion will fail.

  1. it('works with resolves', () => {
  2. expect.assertions(1);
  3. return expect(user.getUserName(5)).resolves.toBe('Paul');
  4. });

async/await

Writing tests using the async/await syntax is also possible. Here is how you’d write the same examples from before:

  1. // async/await can be used.
  2. it('works with async/await', async () => {
  3. expect.assertions(1);
  4. const data = await user.getUserName(4);
  5. expect(data).toBe('Mark');
  6. });
  7. // async/await can also be used with `.resolves`.
  8. it('works with async/await and resolves', async () => {
  9. expect.assertions(1);
  10. await expect(user.getUserName(5)).resolves.toBe('Paul');
  11. });

To enable async/await in your project, install @babel/preset-env and enable the feature in your babel.config.js file.

Error handling

Errors can be handled using the .catch method. Make sure to add expect.assertions to verify that a certain number of assertions are called. Otherwise a fulfilled promise would not fail the test:

  1. // Testing for async errors using Promise.catch.
  2. it('tests error with promises', () => {
  3. expect.assertions(1);
  4. return user.getUserName(2).catch(e =>
  5. expect(e).toEqual({
  6. error: 'User with 2 not found.',
  7. }),
  8. );
  9. });
  10. // Or using async/await.
  11. it('tests error with async/await', async () => {
  12. expect.assertions(1);
  13. try {
  14. await user.getUserName(1);
  15. } catch (e) {
  16. expect(e).toEqual({
  17. error: 'User with 1 not found.',
  18. });
  19. }
  20. });

.rejects

The.rejects helper works like the .resolves helper. If the promise is fulfilled, the test will automatically fail. expect.assertions(number) is not required but recommended to verify that a certain number of assertions are called during a test. It is otherwise easy to forget to return/await the .resolves assertions.

  1. // Testing for async errors using `.rejects`.
  2. it('tests error with rejects', () => {
  3. expect.assertions(1);
  4. return expect(user.getUserName(3)).rejects.toEqual({
  5. error: 'User with 3 not found.',
  6. });
  7. });
  8. // Or using async/await with `.rejects`.
  9. it('tests error with async/await and rejects', async () => {
  10. expect.assertions(1);
  11. await expect(user.getUserName(3)).rejects.toEqual({
  12. error: 'User with 3 not found.',
  13. });
  14. });

The code for this example is available at examples/async.

If you’d like to test timers, like setTimeout, take a look at the Timer mocks documentation.