An Async Example

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

    user.js

    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. });

    __mocks__/request.js

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

    __tests__/user-test.js

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

    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.

    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. // 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. expect.assertions(1);
    9. });

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

    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:

    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 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. });

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

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