bluebird: bluebird logs out "unhandled rejection error" despite rejection being handled by chai-as-promised

I’m moving this issue from domenic/chai-as-promised#97 - we have a user (@ohjames) who is claiming that while using bluebird, and asserting with chai-as-promised that rejection has been handled, bluebird still believes the rejection has not been handled. To quote the OP:

I would have thought this mocha test would work fine:

  // Either I've made a mistake or chai-as-promised is crap...
  it('finds that chai-as-promised is not broken', function() {
    var Promise = require('bluebird')
    var promise = Promise.reject(Error())
    return promise.should.be.rejected
  })

It looks like it passes but check out the stderr after the test…

  User Model
    ✓ finds that chai-as-promised is not broken 
Unhandled rejection Error
    at Error (native)
    at Context.<anonymous> (/home/mega-totoro/projects/cuddle-friends/server/api/user/user.model.spec.js:40:34)
    at callFn (/home/mega-totoro/projects/cuddle-friends/node_modules/grunt-mocha-test/node_modules/mocha/lib/runnable.js:223:21)
    at Test.Runnable.run (/home/mega-totoro/projects/cuddle-friends/node_modules/grunt-mocha-test/node_modules/mocha/lib/runnable.js:216:7)
    at Runner.runTest (/home/mega-totoro/projects/cuddle-friends/node_modules/grunt-mocha-test/node_modules/mocha/lib/runner.js:374:10)
    at /home/mega-totoro/projects/cuddle-friends/node_modules/grunt-mocha-test/node_modules/mocha/lib/runner.js:452:12
    at next (/home/mega-totoro/projects/cuddle-friends/node_modules/grunt-mocha-test/node_modules/mocha/lib/runner.js:299:14)
    at /home/mega-totoro/projects/cuddle-friends/node_modules/grunt-mocha-test/node_modules/mocha/lib/runner.js:309:7
    at next (/home/mega-totoro/projects/cuddle-friends/node_modules/grunt-mocha-test/node_modules/mocha/lib/runner.js:247:23)

Or am I doing something stupid?

here is the LOC where chai-as-promised handles the rejection.

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Reactions: 6
  • Comments: 31 (8 by maintainers)

Most upvoted comments

Hah, well yeah, that’s fun.

Have retested it on both my computers now, and can’t reproduce it anymore either. Ran the test suite in our app, and it doesn’t happen there anymore either.

Guess we’ll file this under the Mulder & Scully category.

I’d recommend to simply use

var p = new Promise( function(resolve,reject) {
  // try-catch is unnecessary in the promise executor
  console.log('code');
  throw new Error('test');
});

p.then(function() {
  console.log('normal');
}, function(reason) {
  console.log('catch', reason);
});

I did this:

sinon.addBehavior('rejects', (stub, val) => {
    // Bluebirds unhandled rejection works by checking if there is no error handler in any attached
    // promise chain as the rejection fires, constructing the promise sync would trigger this
    // mechanism as multiple ticks may pass before an error handler is attached.
    let p;
    stub.returns(new Proxy({}, {
        get (obj, key) {
            if (p) {
                return p[key].bind(p);
            }
            p = Bluebird.reject(val);
            return p[key].bind(p);
        },
    }));
});

To make it more the sscce more reproducible, we added a delay between the declaration of the promise and the should.be.rejected.

Does it makes it easier to solve the problem ?

How to fix this problem? Can we redirect the output of the console.log of the promise under test or redefine bluebird’s rejection handler?

var Promise = require('bluebird');
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
chai.should();

describe('Test', function () {
  it('should work but barks about unhandled rejections', function () {
    var promise = Promise.reject(Error());
    return Promise.delay(1000).then(() => promise.should.be.rejected);
  });
});

@adamreisnz At the risk of saying “works on my machine”… well…

$  cat test.js
var Promise = require('bluebird');
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
chai.should();

describe('Test', function() {
  it('should work but barks about unhandled rejections', function() {
    var promise = Promise.reject(Error());
    return promise.should.be.rejected;
  });
});
$ node -v
v7.2.1

$ npm i chai chai-as-promised mocha bluebird
/some/folder/somewhere
├── bluebird@3.4.6
├── chai@3.5.0
├── chai-as-promised@6.0.0
└── mocha@3.2.0

$ ./node_modules/.bin/_mocha test.js

  Test
    ✓ should work but barks about unhandled rejections


  1 passing (17ms)

@petkaantonov @keithamus

Doesn’t reproduce in node either:

Actually, that example fails for me if I include it inside of an actual test:

var Promise = require('bluebird');
var chai = require('chai');
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
chai.should();

describe('Test', function() {
  it('should work but barks about unhandled rejections', function() {
    var promise = Promise.reject(Error());
    return promise.should.be.rejected;
  });
});

Put it inside a test file and run with Mocha: ./node_modules/mocha/bin/_mocha "test.spec.js"

Result:

Test
    ✓ should work but barks about unhandled rejections
Unhandled rejection Error
    at Context.<anonymous> (/Users/Adam/Sites/bookingpro/server/test.spec.js:10:34)
    at callFn (/Users/Adam/Sites/bookingpro/server/node_modules/mocha/lib/runnable.js:343:21)
    at Test.Runnable.run (/Users/Adam/Sites/bookingpro/server/node_modules/mocha/lib/runnable.js:335:7)
    at Runner.runTest (/Users/Adam/Sites/bookingpro/server/node_modules/mocha/lib/runner.js:444:10)
    at /Users/Adam/Sites/bookingpro/server/node_modules/mocha/lib/runner.js:550:12
    at next (/Users/Adam/Sites/bookingpro/server/node_modules/mocha/lib/runner.js:361:14)
    at /Users/Adam/Sites/bookingpro/server/node_modules/mocha/lib/runner.js:371:7
    at next (/Users/Adam/Sites/bookingpro/server/node_modules/mocha/lib/runner.js:295:14)
    at Immediate.<anonymous> (/Users/Adam/Sites/bookingpro/server/node_modules/mocha/lib/runner.js:339:5)
    at runCallback (timers.js:637:20)
    at tryOnImmediate (timers.js:610:5)
    at processImmediate [as _immediateCallback] (timers.js:582:5)

Running it as a standalone script (without the describe and it wrappers) didn’t trigger the error.

I’m getting these Unhandled rejection errors in a lot of my tests now that used to work fine, so it seems something has happened/changed that this problem has now returned.

This happens with Node 7.1.0 and 7.2.0 for me. Any thoughts?

If you have single consumer scenario it makes no sense to divide the promise chains like above though. And if you have multiple consumers, then each consumer of course should handle their respective errors, in your case consumer 1 didn’t handle it but only consumer 2 did.