1

I am very new to NodeJS.I need some help testing a simple API i have build with Express.

I have the following route in my API:

router.get('/execute', function(req, res, next) {
console.log("Execute Request Query: %s", util.inspect(req.query, false, null));

// Validate Reqest. gremlin is Mandatory field 
if (req == null || req.query.gremlin == null) {
    res.status(400).send(getErrorResponse("Invalid Request", "Request is missing mandatory field: gremlin"));
    return;
}

queryDB(req.query.gremlin, res);
});

This Route calls a shared method queryDB which is making an API call to the Titan DB using its Restful Interface. I am using node_module Restler to make this API Call.

function queryDB(query, res) {
console.log("Constructed Gremlin Query: %s. Querying Titan with URL: %s", util.inspect(query, false, null), titanBaseUrl);

rest.postJson(titanBaseUrl,
    { gremlin: query },
    { headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } }
).on('complete', function(data, response) {
    if (response != null && response.rawEncoded != null && response.statusCode / 100 == 2) {
        console.log("Call successful. Response.rawEncoded: %s", util.inspect(response.rawEncoded, false, null));
        res.send(getResult(response));
    } else {
        console.error("Call failed. Response: %s", util.inspect(response, false, null));
        res.status(500).send(getErrorResponse("Bad Gremlin Response", response));
    }
});
}

Now, I want to test my API's "execute" endpoint. I am able to do this with following:

var www = require("../bin/www");
var superagent = require('superagent');
var expect = require('expect.js');
var proxyquire = require('proxyquire');

describe('server', function() {

before(function() {
    www.boot();
});

describe('Execute', function() {
    it('should respond to GET', function(done) {
        superagent
            .get('http://localhost:' + www.port + "/gremlin/execute?gremlin=99-1")
            .end(function(err, res) {
                expect(res.status).to.equal(200);
                expect(res.body.data[0]).to.equal(98);
                done()
            })
    })
});

after(function() {
    www.shutdown();
});
});

However I am currently making call to my database which I need to mock. I saw some examples online that help you mock node modules that I could use to mock "Restler". However since I am testing an API by calling the endpoint, I am not sure how to mock a module for this.

I looked at the following examples: https://stackoverflow.com/a/33773233/2596762 https://www.terlici.com/2015/09/21/node-express-controller-testing.html etc.

Any help or suggestion is appreciated. Thanks.

Community
  • 1
  • 1
Rahul Dabas
  • 726
  • 2
  • 15
  • 27

2 Answers2

0

I am able to test my API with downstream systems mocked following this SO answer.

I am however not sure if this is the best/only way.

Community
  • 1
  • 1
Rahul Dabas
  • 726
  • 2
  • 15
  • 27
0

The only way I've found is to change app.use('/users', userRoute); with userRoute(app):

// file: main.js
var express = require('express');
var app = express();
var userRoute = require('./user-route');

// Have user route mount itself to the express application, we could pass
// other parameters too, such as middleware, or the mount path
userRoute(app);

Create special module for every route:

// file: user-route.js
var express = require('express');
var users = require('./users');

module.exports = function (app) {
  var route = express.Router();

  // Mount route as "/users"
  app.use('/users', route);

  // Add a route that allows us to get a user by their username
  route.get('/:username', function (req, res) {
    var user = users.getByUsername(req.params.username);

    if (!user) {
      res.status(404).json({
        status: 'not ok',
        data: null
      });
    } else {
      res.json({
        status: 'ok',
        data: user
      });
    }
  });
};

And then you can use proxyquire to mock your dependencies:

// We'll use this to override require calls in routes
var proxyquire = require('proxyquire');
// This will create stubbed functions for our overrides
var sinon = require('sinon');
// Supertest allows us to make requests against an express object
var supertest = require('supertest');
// Natural language-like assertions
var expect = require('chai').expect;

var express = require('express');

describe('GET /ping', function () {
  var app, getUserStub, request, route;

  beforeEach(function () {
    // A stub we can use to control conditionals
    getUserStub = sinon.stub();

    // Create an express application object
    app = express();

    // Get our router module, with a stubbed out users dependency
    // we stub this out so we can control the results returned by
    // the users module to ensure we execute all paths in our code
    route = proxyquire('./user-route.js', {
      './users': {
        getByUsername: getUserStub
      }
    });

    // Bind a route to our application
    route(app);

    // Get a supertest instance so we can make requests
    request = supertest(app);
  });

  it('should respond with a 404 and a null', function (done) {
    getUserStub.returns(null);

    request
      .get('/users/nodejs')
      .expect('Content-Type', /json/)
      .expect(404, function (err, res) {
        expect(res.body).to.deep.equal({
          status: 'not ok',
          data: null
        });
        done();
      });
  });

  it('should respond with 200 and a user object', function (done) {
    var userData = {
      username: 'nodejs'
    };

    getUserStub.returns(userData);

    request
      .get('/users/nodejs')
      .expect('Content-Type', /json/)
      .expect(200, function (err, res) {
        expect(res.body).to.deep.equal({
          status: 'ok',
          data: userData
        });
        done();
      });
  });
});

Big thanks to Evan Shortiss:

http://evanshortiss.com/development/javascript/2016/04/15/express-testing-using-ioc.html

Anton Pegov
  • 1,413
  • 2
  • 20
  • 33