Skip to content
thesarfo

Note

Testing with Jest & Supertest

Setting up Jest as a dev dependency, structuring test files, watch mode, and using Supertest for HTTP assertions against an Express API.

views 0

Software Testing with Jest

First when you want to test with jest, you need to install it as a development dependency

Terminal window
npm install jest --save-dev

NB: You will need to install ‘ts-jest’ and ‘@types/jest’ as development dependencies

And then inside the package.json of the folder in which you installed jest, look for the “test” key inside the scripts object and give it a value of “jest”. See below

"scripts": {
"test": "jest ",
"watch": "nodemon src/server.js",
"start": "node src/server.js"
},

Then, it’s either you create a folder called __tests__ or you create a test file inside the folder of the main file that you want to test. Make sure that the test file has a dot that separated the file name and the “test” word. For instance “example.test.js”

In this example, I created a test file separately, called launches.test.js

and inside this file, there a specific keywords that jest provides that you can use for api testing. these keywords are “describe”, “test”, “expect”, “toBe” and so on

Below is the launches.test.js testing particular routes in the launches_router.js

describe("Test GET /launches", () => {
test("It should respond with 200 success", () => {
const response = 200;
expect(response).toBe(200);
});
});
describe("Test POST /launch", () => {
test("It should respond with 200 success", () => {
// Test logic for POST /launch success
});
test("It should catch missing required properties", () => {
// Test logic for missing required properties
});
test("It should catch invalid dates", () => {
// Test logic for invalid dates
});
});

Upon running the test command, it returns a response like

Terminal window
$ npm test
> server@1.0.0 test
> jest
PASS src/routes/launches/launches.test.js
Test GET /launches
It should respond with 200 success (4 ms)
Test POST /launch
It should respond with 200 success
It should catch invalid dates (1 ms)
Test Suites: 1 passed, 1 total
Tests: 4 passed, 4 total
Snapshots: 0 total
Time: 1.428 s
Ran all test suites.

Let’s say we want our tests to run anytime we update the launch function/route, we can make jest watch our launch route for changes, this is done by adding a watch command in our scripts

"scripts": {
"test": "jest",
"test-watch": "jest --watch",
"watch": "nodemon src/server.js",
"start": "node src/server.js"
},

Now you need to ensure that jest actually makes request to your api and then test the response. For this, you can use the supertest library which brings some convenient http assertions

So you also need to install supertest as a development dependency

Terminal window
npm install supertest --save-dev

And then you require supertest inside each of your test files. I call supertest “request” because it will essentially be sending requests to my api.

const request = require('supertest');

Below is how a supertest testing an api endpoint looks like

const request = require('supertest');
const app = require("../../app");
describe("Test GET /launches", () => {
test("It should respond with 200 success", async () => {
const response = await request(app).get('/launches');
expect(response.statusCode).toBe(200);
});
});

the “request” method takes an argument of app- which is your express server, so you need to require it at the top of your file. And then we make a get request to the “/launches” endpoint, and then we expect the response.statusCode to be 200. note that we have made our callback function asynchronous with the async await syntax

Instead of that long “expect statusCodeToBe 200” line, we can make it shorter. also we can set the content-type we want to make the request to, as well as our get request to our endpoint.

This will be done by chaining all these promises. See below

describe("Test GET /launches", () => {
test("It should respond with 200 success", async () => {
const response = await request(app)
.get('/launches')
.expect('Content-Type', /json/)
.expect(200);
});
});

A post request will look like this

describe("Test POST /launch", () => {
test("It should respond with 201 created", async () => {
const response = await request(app)
.post('/launches')
.send({
mission: "USS Enterprise",
rocket: "NCC 1701-D",
target: "Kepler-186 f",
launchDate: "January 4, 2028",
})
.expect("Content-Type", /json/)
.expect(201)
});
test("It should catch missing required properties", () => {
// Test logic for missing required properties
});
test("It should catch invalid dates", () => {
// Test logic for invalid dates
});
});

Below is another post request but properly formatting the dates

describe("Test POST /launch", () => {
("It should respond with 201 created", async () => {
const response = await request(app)
.post('/launches')
.send(completeLaunchData)
.expect("Content-Type", /json/)
.expect(201);
const requestDate = new Date(completeLaunchData.launchDate).valueOf();
const responseDate = new Date(response.body.launchDate).valueOf();
expect(responseDate).toBe(requestDate);
expect(response.body).toMatchObject(launchDataWithoutDate);const completeLaunchData = {
mission: "USS Enterprise",
rocket: "NCC 1701-D",
target: "Kepler-186 f",
launchDate: "January 4, 2028",
};
const launchDataWithoutDate = {
mission: "USS Enterprise",
rocket: "NCC 1701-D",
target: "Kepler-186 f",
};
test
});
});