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.
You are mocking
req
here, soreq
in your test needs to have all of the properties ofreq
in your code. This would include the logger.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