Test your REST api using Mocha and supertest

One of the important task which most of the developers ignores ( i used to ignore too ) is writing unit tests for your code. Unit test is not just a help to tester or quality assurance team but its the proof of quality of your code.

In this tutorial i am going to cover how to test your REST api’s written in ExpresJS using famous unit testing tool called Mocha and supertest.

What is Mocha ?

Mocha is simple and easy to use test framework. It runs on Node.js and allows you to develop test cases for your program and execute them in serial with proper reporting.

To use mocha i suggest you to install it and as global package using following command.

sudo npm install -g mocha

What is supertest ?

Supertest is library written to test HTTP calls in node.js. So if you want to write test cases which going to do some HTTP calls ( GET, POST, PUT etc ) then this might be the useful tool for you.

Our project :

Let’s develop an expressJS app with some routes and test whether those are giving expected result or not.

Here is package.json :

{
  "name": "MochaTest",
  "version": "0.0.1",
  "dependencies": {
    "body-parser": "^1.13.2",
    "express": "^4.13.1"
  }
}

Install dependencies by running

npm install

on terminal.

Here is Server file.

var express = require("express");
var bodyParser = require("body-parser");
var app = express();
app.use(bodyParser.urlencoded());
app.use(bodyParser.json());
var router = express.Router();

router.get('/',function(req,res){
  res.json({"error" : false, "message" : "Hello !"});
});

router.post('/add',function(req,res){
  res.json({"error" : false, "message" : "success", "data" : req.body.num1 + req.body.num2});
});

app.use('/',router);

app.listen(3000,function(){
  console.log("I am listening at PORT 3000");
})

Writing test cases :

Let’s move ahead and write some unit test for above program. First you need to install mocha, should and supertest in your project. It’s better if we add them in dev dependencies.

1 : Install mocha.

npm install --save-dev mocha

2 : Install should.

npm install --save-dev should

3 : Install supertest.

npm install --save-dev supertest

After running above commands your package.json should look this.

{
  "name": "MochaTest",
  "version": "0.0.1",
  "dependencies": {
    "body-parser": "^1.13.2",
    "express": "^4.13.1"
  },
  "devDependencies": {
    "mocha": "^2.2.5",
    "should": "^7.0.2",
    "supertest": "^1.0.1"
  }
}

Let’s create one folder called “test” and place “test.js” inside it. Just to separate it from rest of the code.

Before writing unit test, let’s discuss how the building block will look.

You need to provide description of unit test using “describe” function and use “it” to define several unit test cases into it. “it” provides us “done” function is used to indicate the end of test case.

Let’s write following unit test case.

  • Access home page – should return response code 200
  • Add router should add two numbers.
  • 404 for other router

Test case 1 : Access home page

var supertest = require("supertest");
var should = require("should");

// This agent refers to PORT where program is runninng.

var server = supertest.agent("http://localhost:3000");

// UNIT test begin

describe("SAMPLE unit test",function(){

  // #1 should return home page

  it("should return home page",function(done){

    // calling home page api
    server
    .get("/")
    .expect("Content-type",/json/)
    .expect(200) // THis is HTTP response
    .end(function(err,res){
      // HTTP status should be 200
      res.status.should.equal(200);
      // Error key should be false.
      res.body.error.should.equal(false);
      done();
    });
  });

});

Assuming you have installed mocha globally, run your node program and listen on port 3000. Open another tab and run

mocha

to start test.

Here is screenshot.

Screen Shot 2015-07-12 at 8.18.20 pm

Test case 2 : Add router should add two numbers.

var supertest = require("supertest");
var should = require("should");

// This agent refers to PORT where program is runninng.

var server = supertest.agent("http://localhost:3000");

// UNIT test begin

describe("SAMPLE unit test",function(){

  // #1 should return home page

  it("should return home page",function(done){
     -------------------------------------
  });

  it("should add two number",function(done){

    //calling ADD api
    server
    .post('/add')
    .send({num1 : 10, num2 : 20})
    .expect("Content-type",/json/)
    .expect(200)
    .end(function(err,res){
      res.status.should.equal(200);
      res.body.error.should.equal(false);
      res.body.data.should.equal(30);
      done();
    });
  });

});

Here is test case response.

Screen Shot 2015-07-12 at 8.25.27 pm

Test case 3 : 404 Error.

var supertest = require("supertest");
var should = require("should");

// This agent refers to PORT where program is runninng.

var server = supertest.agent("http://localhost:3000");

// UNIT test begin

describe("SAMPLE unit test",function(){

  // #1 should return home page

  it("should return home page",function(done){
      ---------------------------------
  });

  it("should add two number",function(done){
      ---------------------------------
  });

  it("should return 404",function(done){
    server
    .get("/random")
    .expect(404)
    .end(function(err,res){
      res.status.should.equal(404);
      done();
    });
  })
});

Here is the output.

Screen Shot 2015-07-12 at 8.29.21 pm

Let’s see some failure case

Just change the equal value in second test to other than 30 and see the response. Like this.

var supertest = require("supertest");
var should = require("should");

// This agent refers to PORT where program is running.

var server = supertest.agent("http://localhost:3000");

// UNIT test begin

describe("SAMPLE unit test",function(){

  // #1 should return home page

  it("should return home page",function(done){
    --------------------------------
  });

  it("should add two number",function(done){

    //calling ADD api
    server
    .post('/add')
    .send({num1 : 10, num2 : 20})
    .expect("Content-type",/json/)
    .expect(200)
    .end(function(err,res){
      res.status.should.equal(200);
      res.body.error.should.equal(false);
      res.body.data.should.equal(40);
      done();
    });
  });

  it("should return 404",function(done){
      ---------------------------
  })
});

You should get one failure test case.

Screen Shot 2015-07-12 at 8.32.16 pm

Conclusion:

Writing unit test is like never-ending process. You can write almost all kind of combination of test cases. You should learn and start writing test cases right after you finish one particular module,don’t wait for the project to finish.

Shahid (UnixRoot) Shaikh

Hey there, This is Shahid, an Engineer and Blogger from Bombay. I am also an Author and i wrote a programming book on Sails.js, MVC framework for Node.js.

Related Posts

24 Comments

  1. In last case we are getting Uncaught Exception: excepted 30 to be 40. How to handle these this Exception in mocha, Please tell me

  2. Thanks you for nice tutorial.
    But I have a problem: My API will response ‘[]’ if after query database, result haven’t data or have a error. And I want to catch error from mocha when I request with wrong type of data.
    Thanks and please help me!

  3. what is the naming convention for unit test file name??
    Like in a big module: module_spec_methodName.js
    for ex: string_spec_match.js
    Is it right??

  4. Getting below error after .double callback warning.
    Uncaught TypeError: Cannot read property ‘status’ of undefined.

  5. Ok, I am wondering why you stated the expect(200) in Step 1. But then in that same script, in the .end statement is where you are testing the actual response status coming back from the server. Is there a reason for doing both??

  6. @Anthony Jackson
    Actually, he doesn’t only do it in step 1, but in the others as well. For example in step 3 with 404.

    From what I could see the expect doesn’t actually do anything used in this way. Try to change the value in the expect and the result of the test will not change. I’m not sure either why the expect is used in this examples?

    1. server.expect() i believe look for HTTP code.

      in case one mentioned by @Anthony, we are checking for “good” use and we are getting the response. Response should have header code 200 which is OK in http verb.

      Same goes for case you mentioned, 404 is not found object.

  7. Great, tell me one more thing, how to handle flash messages ?
    On each `error` or `success` of API I’m redirecting on same page with flash messages.
    I can write like this `res.header[‘location’].should.include(‘/home’)`.
    But I need to verify either it is redirecting with error or success.
    Thanks..!!

  8. This is totally misleading – these are not unit test’s – these are integration tests which run against your node server

  9. I am new to node .. I am getting the following error ..SAMPLE unit test
    1) should return home page
    0 passing (38ms)
    1 failing

    1) SAMPLE unit test should return home page:
    Uncaught TypeError: Cannot read property ‘should’ of undefined
    at Test. (Tests/test.js:24:21)
    at Test.assert (node_modules/supertest/lib/test.js:179:6)

    Any idea what is happening..

    thanks

    1. Hey Raj, you are using ‘should’ against null or undefined value. Make sure that the response object key/property has a value. For instance, ‘res.body.error’ might giving you a null value or undefined.

      Hope this helps.

  10. Nice article.
    One question: How do we display a customised error message when one of the response parameter/field is missing (as we get Assertion error in this case and need a customised error to show)

Leave a Reply

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