Search code examples
javascriptnode.jschaisinon

Not able to call the res.send()


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.

validate.js file

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.

util.js file

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);
}

test_util.js file

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.


Solution

  • 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