Cannot unit test JavaScript functions with Tape/ Sinon

660 Views Asked by At

I have a module that I want to test using Tape and Sinon. Unfortunately I'm not doing very well. Here is the module code:

let config = require('./config');
let request = require('request');
let restify = require('restify');

let certificateUtils = require('utilities');

const validateTheToken = function (token, requestId, callback) {

  const options = {
    url: config.userServiceRootUrl + config.validationPath,
    method: 'POST',
    headers: {
      'token': token,
      'caller': config.callingService,
      'x-request-id': requestId
    }
  };

  if (typeof process.env.CA_STORE !== 'undefined') {
    const certAuth = process.env.CA_STORE + '/trustedCA.pem';
    options.ca = certificateUtils.getAuthorisedCerts(certAuth);
  }

  request(options, function (error, response, body) {
    callback(error, response, body);
  });
};

// add token validation middleware
const authenticateTheToken = function (req, res, next) {
  if (config.enableTokenValidation) {

    const receivedToken = getToken(req);
    if (!receivedToken) {
      return next(new restify.NotAuthorizedError('No token'));
    }

    validateTheToken(receivedToken, req.requestId, function (err, response, body) {
      if (err || response.statusCode != 200) {
        req.logger.error({
          err: err,
          response: response ? {
            statusCode: response.statusCode,
            statusMessage: response.statusMessage,
            body: body
          } : undefined,
        }, 'validation failed');
        return next(new restify.NotAuthorizedError('Not a valid token'));
      } else {
        return next();
      }
    });
  }
  else {
    return next();
  }
};

function getTheToken(req) {


  if (req.headers.token) {
    return req.headers.token;
  } else if (req.headers.user) {
    req.logger.warn({req, user: req.headers.user}, `request was sent with header 'user'`);
    try {
      return JSON.parse(req.headers.user).token;
    } catch (e) {
      req.logger.warn({user: req.headers.user}, `is not valid JSON`);
      return null;
    }
  } else {
    return null;
  }
}

module.exports = {getTheToken, authenticateTheToken};

How could I first of all unit test that authenticateTheToken has been called? Here is my attempt: test('accessed authenticateTheToken', function (t) {

 const tokenAuthentication = require('../tokenAuthentication');
 const authenticateToken = tokenAuth.authenticateToken;

 let req = {
    headers: {
        token: 1
     }
 };
 let res = {};
 let next = {};

 let stub = sinon.stub(tokenAuth, 'getToken');

 stub.yields('next');

 authenticateToken(req, res, next);

 t.equal(authenticateToken.callCount, 1);
 t.end();
 });

When I run the test I cam getting the following error:

C:\source\my-project\tokenAuthentication.js:40
    req.logger.error({
              ^

TypeError: Cannot read property 'error' of undefined
    at C:\source\my-project\tokenAuthentication.js:40:19
    at Request._callback (C:\source\my-project\tokenAuthentication.js:25:5)
    at self.callback (C:\source\my-project\node_modules\request\request.js:188:22)
    at emitOne (events.js:96:13)
    at Request.emit (events.js:188:7)
    at Request.init (C:\source\my-project\node_modules\request\request.js:234:17)
    at new Request (C:\source\my-project\node_modules\request\request.js:130:8)
    at request (C:\source\my-project\node_modules\request\index.js:54:10)
    at validateTheToken (C:\source\my-project\tokenAuthentication.js:24:3)
    at authenticateTheToken (C:\source\tokenAuthentication.js:38:5)


npm ERR! Test failed.  See above for more details.
1

There are 1 best solutions below

0
Explosion Pills On

You are mocking req here, so req in your test needs to have all of the properties of req in your code. This would include the logger.

req = {
  ...
  logger: {
    warn: () => {},
    error: () => {},
  }
}

req probably has a lot of properties, so you may either want to create a real Request object or use another library for mocking http requests such as nock