I am working on a Node.js application.
This is a code of validate.js file, where I have defined a class Validate and static method validateTicket and at the bottom exported the class.
const request = require("request");
const config = { urlBase: "" };
class Validate {
static validateTicket = (ticket) => {
const options = { url: config.urlBase + ticket, json: true, rejectUnauthorized: false };
return new Promise((resolve, reject) => {
request.get(options, (error, response, body) => {
if (error) {
reject(error);
return;
}
if (response) {
resolve(response);
return;
}
reject(null);
});
});
};
}
module.exports = Validate;
This is the main utility file where I am importing the validate.js file and there are 3 functions validateTicketReqs
, to_json
, and sendErrorResponse
.
validateTicketReqs
function do validation on response received from class method.
const validate = require('./validate.js');
function validateTicketReqs(req, res, next, flag, num) {
let payload = req.body;
let ticket= (payload.ticket) ? payload.ticket: null;
let error_msg = 'Failed to obtain a successful response '
validate.validateTicket(ticket).then(
(resolution) => {
let json = to_json(resolution); // function will return null value for json
if (json === null || !('body' in json)) {
return sendErrorResponse(req, res, 500, 'error');
}
...
})
function sendErrorResponse(req, res, code, msg) {
let resBody = {
msg: msg
};
res.status(code);
res.send(resBody);
}
const validate = require('./validate.js');
describe("Check", () => {
it("should fail due to error", (done) => {
let req = {
authData: {'user_id': "mock"},
body: {"num": "mock", "tikcet": "mock"},
request_id: 'mock'
};
let res = {send: sinon.spy(), status: sinon.spy()};
let next = sinon.spy();
mock_buffer = {
toJSON : function() { return {body: {environment: 'mock', status: 'mock'}}},
statusCode: 500
}
const validateTicket= sinon.stub(validate, 'validateTicket')
validateTicket.resolves(mock_buffer)
util.valdateTicketReqs(req, res, next, flag, "mock" );
expect(res.send.calledOnce).to.be.true; ##not getting called
expect(res.send.firstCall.args[0].statusCode).to.equal(500); ##not getting called
util.valdateTicketReqs.restore();
validate.validateTicket.restore();
done();
});
});
The problem I am facing is that (res.send.calledOnce)
value is coming as false. I am expecting that res.send()
should be called at least once but it is not. Please advise what is the problem here. Let me know if you have a query on the question.
The issue is the expect
method is called before the test case finished. The return value of your validate.validateTicket
method is a promise, it's asynchronous method. You need return it so that test runner will know if the test case is done.
E.g.
validate.ts
:
const request = require("request");
const config = { urlBase: "" };
class Validate {
static validateTicket = (ticket) => {
const options = { url: config.urlBase + ticket, json: true, rejectUnauthorized: false };
return new Promise((resolve, reject) => {
request.get(options, (error, response, body) => {
if (error) {
reject(error);
return;
}
if (response) {
resolve(response);
return;
}
reject(null);
});
});
};
}
module.exports = Validate;
util.ts
:
const validate = require("./validate");
function to_json(data) {
return null;
}
function sendErrorResponse(req, res, code, msg) {
const resBody = {
msg: msg,
};
res.status(code);
res.send(resBody);
}
export function validateTicketReqs(req, res, next, flag, num) {
const payload = req.body;
const ticket = payload.ticket ? payload.ticket : null;
const error_msg = "Failed to obtain a successful response ";
return validate.validateTicket(ticket).then((resolution) => {
const json = to_json(resolution);
if (json === null || !("body" in json)) {
return sendErrorResponse(req, res, 500, "error");
}
});
}
util.spec.ts
:
import sinon from "sinon";
import { expect } from "chai";
import * as util from "./util";
const validate = require("./validate");
describe("Check", () => {
it("should fail due to error", async () => {
const req = {
authData: { user_id: "mock" },
body: { num: "mock", tikcet: "mock" },
request_id: "mock",
};
const res = {
send: sinon.spy(),
status: sinon.spy(),
};
const next = sinon.spy();
const flag = "";
const mock_buffer = {
toJSON: function() {
return { body: { environment: "mock", status: "mock" } };
},
statusCode: 500,
};
const validateTicketStub = sinon.stub(validate, "validateTicket").resolves(mock_buffer);
await util.validateTicketReqs(req, res, next, flag, "mock");
expect(res.send.calledOnce).to.be.true;
expect(res.status.firstCall.args[0]).to.equal(500);
sinon.assert.calledOnce(validateTicketStub);
validateTicketStub.restore();
});
});
Unit test result with coverage report:
Check
✓ should fail due to error
1 passing (19ms)
--------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
--------------|----------|----------|----------|----------|-------------------|
All files | 76.09 | 30 | 63.64 | 75.56 | |
util.spec.ts | 94.12 | 100 | 66.67 | 93.75 | 22 |
util.ts | 100 | 50 | 100 | 100 | 9,14 |
validate.ts | 37.5 | 0 | 25 | 37.5 |... 12,15,16,17,20 |
--------------|----------|----------|----------|----------|-------------------|
Source code: https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/59037819