Search code examples
javascriptnode.jsasynchronousbluebird

Unhandled rejection Error. Even though tests are passing


I'm testing this function:

UserController.prototype.getDashboard = function getDashboard(req, res, next) {
  let pages, user;

  return this.User.findById(req.user.id)
    .populate('club')
    .execAsync()
    .then(dbUser => {
      user = dbUser;
      FB.setAccessToken(user.token);

      return FB.getAsync('me/accounts')
    })
    .then(fbPages => {
      pages = fbPages.data;

      return Promise.all(pages.map(page => {
        return FB.getAsync(`${page.id}/events`)
          .then(events => events)
          .catch(e => next(Boom.wrap(e)));
      }))
    })
    .then(events => {
      let entity = {
        user,
        pages: _.map(pages, (page, i) => _.assign({}, page, { events: events[i].data }))
      };

      return res.send(entity);
    })
    .catch(err => next(Boom.wrap(err)));
};

But when I test it, even though it passes, I get Unhandled rejection Error

This is my test:

 it('handles errors', (done) => {
  let mockError = new Error('test-error');
  let mockRequest = { user: { id: mockUser._id }};
  let mockNext = td.function();
  let capture = td.matchers.captor();

  td.replace(FB, 'getAsync');
  td.when(FB.getAsync('me/accounts'))
    .thenReturn(Promise.resolve(usersTestData.getDashboard.pages));

  td.when(FB.getAsync(`1769754093273789/events`))
    .thenReturn(Promise.resolve(usersTestData.getDashboard.events[0]))

  // Promise rejection was handled asynchronously
  td.when(FB.getAsync(`731033223716085/events`))
    .thenReturn(Promise.reject(mockError))

  td.when(mockNext(Boom.wrap(mockError)))
    .thenDo(() => { done() });

  controller.getDashboard(mockRequest, _.noop, mockNext);
});

The weird part, is that it passes. So the mockNext is being called with what I expected but I get a log in the console with the unhandled rejection. I've tried to handle .catch for each value of the mapping, but it still shows the same error (warning?).

I'm using Bluebird promises, mongoose(promisified) and testdouble. BTW this is the log from the console afte running the test:

dashBoard
Unhandled rejection Error: test-error
✓ handles errors

Solution

  • After a lot of trial and error I found what was going on. The problem had to do with testdouble API .thenReturn().

    The error appeared if .thenReturn(Promise.reject(...)) I configured td to use Bluebird promises and used their API for promises .thenReject(...). The result test code would be:

    td.config({ promiseConstructor: require('bluebird') });
    
    it('handles errors', (done) => {
      let mockError = new Error('test-error');
      let mockRequest = { user: { id: mockUser._id }};
      let mockNext = td.function();
      let capture = td.matchers.captor();
    
      td.replace(FB, 'getAsync');
      td.when(FB.getAsync('me/accounts'))
        .thenReturn(Promise.resolve(usersTestData.getDashboard.pages));
    
      td.when(FB.getAsync(`1769754093273789/events`))
        .thenResolve(usersTestData.getDashboard.events[0])
    
      td.when(FB.getAsync(`731033223716085/events`))
        .thenReject(mockError)
    
      td.when(mockNext(Boom.wrap(mockError)))
        .thenDo(() => { done() });
    
      controller.getDashboard(mockRequest, _.noop, mockNext);
    });
    

    This test would work with no warnings.