Back to Blog

MERN Jest Testing (Part 6)

Sayed Farid Qattali

Testing APIs with SuperTest

SuperTest is a Node.js library for making http requests. SuperTest can be used to test external or internal APIs. With SuperTest we can test both REST and GraphQL APIs.

How to install supertest

install supertest library and add it as a dev dependency using the following command:


npm install --save-dev supertest

Or you can use yarn to install supertest:


yarn add --dev supertest

How to initialize supertest

After importing  supertest, there are two approaches to initialize supertest.

  1. The first approach is to pass the URL of your running server or deployed project to the supertest. As the following:

const request = require('supertest');

const server = request('https://example.com');

In the above snippet the supertest library is imported and its reference is stored in request variable. Then supertest is initialized using URL and stored in server variable.

  1. The second approach is to pass express app object to the supertest. In this approach if the server is not running, supertest will create a running instance of the server.

const request = require('supertest');
const express = require('express');
	
const app = express();	
const server = request(app);

In the above snippet we imported supertest and express.Then, created an express app and finally passed the app instance to supertest.

In the second approach,  you can also import your already created express app and  pass it to supertest as following:


const request = require('supertest');
const app = require('../../server');

const server = request(app);

In the above snippet, we have imported the express app instance from server.js and then passed it to supertest. Make sure that you export the app instance inside server.js.

After initializing supertest, you can use its reference to send any Http request( GET, POST, PUT, DELETE, etc).

The following example sends a GET request to ‘/api/v1/users’ endpoint:


// supertest initialization
server.get('/users')

<aside>💡 Use the first approach for testing external APIs and the second approach for testing internal APIs.

</aside>

How to test an endpoint using supertest?

In order to test an endpoint using supertest, we should send a request to the endpoint, then we should do our expectation on the response of the request.

For the expectation part, we can use the built-in expectmethod of supertestitself or use the expect method of jest.

Example 1

In this example, we are going to test /users endpoint. Sending a GET request to /users returns list of users.

test/routes/users.test.js


const request = require("supertest");
const app = require("../../server");
const { UsersModel } = require("../../models")

let user;

describe("Test users routes", () => {
  const server = request(app);
	
	beforeAll(async () => {
		user = await UsersModel.create({username:"Jame", email: "james@gmail.com", name: "Jame", createdAt: new Date()});
    })

	afterAll(async () => {
		await UsersModel.deleteMany();
	})

  describe("Test /users", () => {
    it("should return list of users", (done) => {
      server
        .get("/users")
        .set("Content-Type", "application/json")
        .set("Accept", "application/json")
        .end(async (err, result) => {
          if (err) {
            done(err);
          }
		      expect(result.body.length).toBe(1);
          expect(result.body[0].username).toBe(user.username);
          expect(result.body[0].email).toBe(user.email);
          expect(result.body[0].name).toBe(user.name);

          done();
        });
    });    
  });
});

The above code snippet can be described as following:

  1. We imported supertest library for making http requests, our express app instance to pass it as a server for supertest as well as UserModel to create users for our tests and remove them at the end of tests.
  2. We initialized supertest within describe block and assigned it to server variable to use it later for making requests.
  3. In the beforeAll block we created a user in order to have required data for our tests. Then in the afterAll block we deleted all users, to make our database clean after tests are finished.
  4. Within the it block is the actual code for making an http request and expecting our desired results. In server.get("/users") we used supertest instance to make a GET http request to /users route. The .set("Content-Type", "application/json")  and .set("Accept", "application/json") are used for setting Content-Type and Accept headers for the request. The .end method of supertest which accepts a callback with (err, res) parameters for handling request errors and response, is used to finalize the request and call the API server. We are checking for errors, if any exist. Finally we are expecting our desired outcome on the response of request.

<aside>💡 Use supertest set method to set http request headers.

</aside>

Example 2

In this example we are going to test POST request to /users endpoint. Sending a POST request to /users creates a new user which accepts username, email, and name fields to be passed as body of endpoint.

<aside>💡 In order to send required body data of an endpoint, we should use the sendmethod of supertest.

</aside>

test/routes/users.test.js


// ...
it("should create new user", (done) => {
		const newUser = {
			username: "Joe12",
			email: "joe@gmail.com",
			name: "Joe"
		};
      server
      .post("/users")
      .set("Content-Type", "application/json")
      .set("Accept", "application/json")
	    .send(newUser)
      .end(async (err, result) => {
         if (err) {
           done(err);
         }
        expect(result.body.username).toBe(newUser.username);
        expect(result.body.email).toBe(newUser.email);
        expect(result.body.name).toBe(newUser.name);

        done();
        });
    });
    

Example 3

In this example, we are going to send a request to /users endpoint, filter list of users according to date they joined by passing a query parameter and test the response.


//...
it("should return list of users", (done) => {
        server
          .get("/users")
          .query({"createdAt": new Date()})
          .set("Content-Type", "application/json")
          .set("Accept", "application/json")
          .end(async (err, result) => {
            if (err) {
              done(err);
            }
            expect(result.body.length).toBe(2);
            expect(result.body[0].username).toBe(user.username);
            expect(result.body[0].email).toBe(user.email);
            expect(result.body[0].name).toBe(user.name);

            done();
          });
    });
    

In the above example, we have used query method of supertest to pass query parameters.

<aside>💡 Use query method from supertest to pass query parameters to a request.

</aside>

We can make DELETE, PUT, and PATCH http requests using supertest like we did in the 3 previous examples and test response of the request.

Supertest API Reference

Share on social media: