Back to Blog

MERN Jest Testing (Part 8)

Aqida Haidari

Testing Asynchronous Code

When you have code that runs asynchronously, Jest needs to know when the code it is testing has completed before moving to another test.

We are going to test the below function that runs asynchronously and gets data from API.


const AllUsers = async (req, res) => {
  try {
    let data = await UserService.getUsers();
    return res.send(data);
  } catch (error) {
    errorHandler(res, error);
  }
};

In the above code snippet AllUsers handle the result of fetched data by getUsers from database. We have used the response of the GET request (res) to send the result or handle the error of the getUsers().

There are three approaches to handle this:

1: Using Callbacks

To test asynchronous code using callbacks, you just need to put the test in a function with a single argument called done. Jest will wait until the done ****callback is called before finishing the test.

test/router/users.test.js


describe("GET /users/", () => {
      it("should return all users using callback",  (done) => {
        server.get("/users/")
        .then((response) => {
          expect(response.statusCode).toBe(200);
          done();
        })
      });
    });
    

If done() callback is never called, the test will fail with no error.

2: Using Promises

To write a test using promise, you need just to return a promise from your test. The below test returns a promise that is supposed to resolve a response and Jest will wait to resolve and if rejected test will fail automatically.

test/router/users.test.js


describe("GET /users/", () => {
    it("should return all users using promise",  () => {
      return server.get("/users/")
      .then(response => {
        expect(response.statusCode).toBe(200);
      })
    });
  });
  

3: Using Async/Await

If your code uses Async/Await, you can use these in your tests as well.

To write an Async test, use the async keyword in front of the function passed to test.

code example:

test/router/users.test.js


describe("GET /users/", () => {
    it("should return all users using async/await", async () => {
      const response = await server.get("/users/");
      expect(response.statusCode).toBe(200);
    });
  });
  

<aside>💡 Jest will throw an error, if the same test function is passed a done() callback and returns a promise. This is done as a precaution to avoid memory leaks in your tests.

</aside>

Resolves/ Rejects matchers

You can also use resolves and rejects matchers to test asynchronous code. And jest will wait for that promise to resolve or reject it.


const AllUsers = (req, res) => {
  return new Promise((resolve, reject) => {
      resolve('yes')
  })
}

it('should resolves',() => {
    expect.assertions(1)
    return expect(AllUsers()).resolves.toBe('yes')
 })
 

In the above test  expect.assertions(1) used in order to verify that a certain number of assertions are called during the test. or you can use expect.hasAssertions() instead of expect.assertions(number)  which verifies that at least one assertion is called during a test.

If you don't add expect.assertions(number) or expect.hasAssertions() to verify that assertions are called a fulfilled promise will not fail the test.

You can also combine resolves and rejects with async/await :


describe("GET /users/", () => {
      it("resolves all users with no error", async () => {
        expect.assertions(1);
        const response = server.get("/users/");
        await expect(response).resolves.not.toThrowError()
    });
 });
 

Share on social media: