fbpx

Lately, I have been working with NodeJS to build APIs. Testing is an integral part of any software building process and as such, I wanted to unit test my APIs. I have done API testing in Java before but never in NodeJS….at least until now. Testing Node API’s is not quite as straightforward as testing other areas of your code. However, I now know how to unit test NodeJS APIs and in this post I will talk about

  1. A sample problem to build an API
  2. TheN NodeJS code to solve that problem
  3. The code to unit test the API

Problem

There’s a popular todo list app that needs to expose it’s resources via a REST API. In addition to that, it’s goal is to maintain it’s user’s entertained by telling them a joke every once a while.

Solution

Based on the above problem, it can be summarised that the API will have endpoints to get all todo, a todo by id and a joke. Doesn’t seem that complicated does it? Let’s write some NodeJS code for it

NodeJS API

To illustrate the concepts of this post, let’s mock the todo data but retrieve the jokes from an external URL.

const express = require("express");
const app = express();
const https = require("https");
const port = 3000;

function allTodos() {
    return [
        {id: 1, name: "Finish writing a blogpost"},
        {id: 2, name: "Make chickpea curry for dinner"},
        {id: 3, name: "Wake up at 5:30am"},
    ];
}

app.get("/", (req, res) => {
    res.send({date: new Date(), msg: "Hello Node"});
});

app.get("/todo", (req, res) => {
    res.send(allTodos());
});

app.get("/todo/:id", (req, res) => {
    const todoId = Math.abs(req.params.id);
    let todos = allTodos();
    let todo = todos.find(t => t.id === todoId);
    res.send(todo);
});

app.get("/joke", (req, res) => {
    const url = "https://api.chucknorris.io/jokes/random";
    https.get(url, (response) => {
        let data = '';
        /* keep appending data to chunks as we receive it */
        response.on('data', (chunk) => {
            data += chunk;
        });
        response.on('end', () => {
            res.send(data);
        });
    })
});

app.listen(port, () => {
    console.log(`Listening on port => ${port}`);
});

module.exports = app;

The above code makes sense right? It’s a simple NodeJS app that uses Express to expose some data.

Like the blog? Subscribe for updates

A little bit about Jokes API

The nature of our jokes API is such that every time we call it, it returns a random Chuck Norris Joke. Therefore a test for this API would need to compare jokes retrieved by two API calls and ensure they are different.

Testing the API

Testing this API would involve checking both the network response as well as the data received. To help with all the testing, the code below makes use of Jest and supertest. 

Jest

Jest as they call it, is a “delightful Javascript testing with the focus on simplicity…”. It was developed at Facebook and it is quite easy to get started with. More info in the getting started official docs

supertest

A library to help assert network requests through another library superagent. This helps in testing aspects of network requests such as status codes for a network response and all. Having a read of the official docs for supertest is highly recommended.

Test code for Todo and Jokes API

The code to test, is below and while it’s assumed to be self-explanatory, it may not be in which case please leave a comment below with any questions that you may have. 

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

describe("Test todo methods", () => {

    it("should reeturn all todos", async done => {
        await request(app)
        .get("/todo")
        .expect(200)
        .then((response) => {
            expect(response.body.length).toBe(3);
        });
        done();
    });

    it(`Should returns a todo with id:${2}`, async done => {
        await request(app)
        .get("/todo/2")
        .expect(200)
        .then((response) => {
            expect(response.body.name).toBe("Make chickpea curry for dinner");
        });
        done();
    });
});
describe("Test responses from querying an external API", () => {

    it("Should retrieve a random Chuck Norris joke",  async done => {
        let jokeResp = await request(app).get("/joke");
        let joke = JSON.parse(jokeResp.text);
        expect(joke.value).toBeTruthy();
        done();
    });
    it("Should not return the same 2 jokes",  async done => {
        let joke1 = await request(app).get("/joke");
        let joke2 = await request(app).get("/joke");
        let j1 = JSON.parse(joke1.text);
        let j2 = JSON.parse(joke2.text);
        expect((j1.value === j2.value)).toBeFalsy();
        done();
    });
});

Package.json

The above code has been tested with the following package.json file, while you can find the package.json file from this Github repo. This is what it looks like

api testing package.json for testing nodejs api with jest & supertest on Github

package.json file for this project

Summary

Testing is an important software development practice that many organisations ignore. It makes sense though, as software engineers often find themselves very busy trying to meet deadlines in this ever growing digital world. Hence, testing is often an afterthought for a lot of organisations but I reckon we should all take a step back and budget some time to write tests. Think about it, software will continue to grow and having tests in place makes it easier to onboard new developers. Having tests provides benchmark or the current “state of the art” in regards to the system to new developers.

The goal of this post was to provide a basic example of how to not only write APIs with NodeJS but also test them. The simple scenario provided illustrates the point of how writing tests is not that complex. Hopefully this encourages you, the readers of this post to write more tests in your development effort.

Like the blog? Subscribe for updates

As usual, if you find any of my posts useful support me by  buying or even trying one of my apps on the App Store. 

https://mydaytodo.com/apps/

Also, if you can leave a review on the App Store or Google Play Store, that would help too.


0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *