2

I'm trying to unit test a controller method with mocha + chai + sinon, but I'm struggling to understand how the assertion works with these async methods. Here is my test:

it('should fetch all registered books and send them as json', (done) => {
  res.json = sandbox.spy();
  const books = [];

  BookMock.expects('find').withArgs()
    .resolves(books);

  booksController.index(req, res, () => {
    res.json.should.have.been.calledWith(200, { data: books });
    done();
  });
});

The problem with this test is that if I change the assertion to expect a 300 instead of 200 parameter, for example, my test will stop (fail) and never call done(), leading to a generic failure which tells nothing more than a 'Test failed because done was never called', which says nothing related to the reason the test failed at all.

If I keep the test like that and my controller method does everything good, the test passes and it's all ok, but if the controller does anything wrong, the test fails and doesn't tell me the reason it failed (which should be "res.json was not called with bla bla bla parameters").

I am also not sure this is the correct way to unit test controller methods, since they don't return a Promise I can't use chai-as-promised or promise chains at all, so I used the next() callback (which always gets called using restify) to make the assertion, that might not be right, so I'm open to a full refactor to make this test the most correct.

Thank you in advance!

1 Answers1

2

Digging a little bit more I've found this answer in other question: https://stackoverflow.com/a/26793989/4233017

So I updated my code and wrapped the assertion in a try/catch, ending up like this:

it('should fetch all registered books and send them as json', (done) => {
  res.json = sandbox.spy();
  const books = [];

  BookMock.expects('find').withArgs()
    .resolves(books);

  booksController.index(req, res, () => {
    try {
      res.json.should.have.been.calledWith(200, { data: books });
      done();
    } catch (e) {
      done(e);
    }
  });
});

Now when the test fails it gives me the correct error message. I could also do it with booleans as the answer says, but I think it's better this way.

Any other solution is still very much appreciated.