jbernal jbernal - 3 months ago 6
Node.js Question

How to unit test a function which calls another that returns a promise?

I have a node.js app using express 4 and this is my controller:

var service = require('./category.service');

module.exports = {
findAll: (request, response) => {
service.findAll().then((categories) => {
response.status(200).send(categories);
}, (error) => {
response.status(error.statusCode || 500).json(error);
});
}
};


It calls my service which returns a promise. Everything works but I am having trouble when trying to unit test it.

Basically, I would like to make sure that based on what my service returns, I flush the response with the right status code and body.

So with mocha and sinon it looks something like:

it('Should call service to find all the categories', (done) => {
// Arrange
var expectedCategories = ['foo', 'bar'];

var findAllStub = sandbox.stub(service, 'findAll');
findAllStub.resolves(expectedCategories);

var response = {
status: () => { return response; },
send: () => {}
};
sandbox.spy(response, 'status');
sandbox.spy(response, 'send');

// Act
controller.findAll({}, response);

// Assert
expect(findAllStub.called).to.be.ok;
expect(findAllStub.callCount).to.equal(1);
expect(response.status).to.be.calledWith(200); // not working
expect(response.send).to.be.called; // not working
done();
});


I have tested my similar scenarios when the function I am testing returns itself a promise since I can hook my assertions in the then.

I also have tried to wrap controller.findAll with a Promise and resolve it from the response.send but it didn't work neither.

Answer

You should move your assert section into the res.send method to make sure all async tasks are done before the assertions:

var response = {
   status: () => { return response; },
   send: () => {
     try {
       // Assert
       expect(findAllStub.called).to.be.ok;
       expect(findAllStub.callCount).to.equal(1);
       expect(response.status).to.be.calledWith(200); // not working
       // expect(response.send).to.be.called; // not needed anymore
       done();
     } catch (err) {
       done(err);
     }
   },
};
Comments