Closed danielesegato closed 5 years ago
I'm having a similar problem. Here is some code to reproduce the potential bug:
var Promise = require('bluebird');
async function test() {
await rejection().error(err=>{
console.error(err);
});
}
test()
function rejection() {
return new Promise((resolve, reject)=>{
reject(new Error('test'));
}).error(err=>{
console.error(err);
return err;
})
}
It produces the following error:
(node:16566) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: test
(node:16566) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Without using async/await a similar error is produced:
var Promise = require('bluebird');
function test() {
rejection().error(err=>{
console.error(err);
});
}
test()
function rejection() {
return new Promise((resolve, reject)=>{
reject(new Error('test'));
}).error(err=>{
console.error(err);
return err;
})
}
Error:
Unhandled rejection Error: test
at Promise (/sandbox/promiserejectionbug/index2.js:14:12)
at Promise._execute (/sandbox/promiserejectionbug/node_modules/bluebird/js/release/debuggability.js:303:9)
at Promise._resolveFromExecutor (/sandbox/promiserejectionbug/node_modules/bluebird/js/release/promise.js:483:18)
at new Promise (/sandbox/promiserejectionbug/node_modules/bluebird/js/release/promise.js:79:10)
at rejection (/sandbox/promiserejectionbug/index2.js:13:10)
at test (/sandbox/promiserejectionbug/index2.js:5:3)
at Object.<anonymous> (/sandbox/promiserejectionbug/index2.js:10:1)
at Module._compile (module.js:624:30)
at Object.Module._extensions..js (module.js:635:10)
at Module.load (module.js:545:32)
at tryModuleLoad (module.js:508:12)
at Function.Module._load (module.js:500:3)
at Function.Module.runMain (module.js:665:10)
at startup (bootstrap_node.js:187:16)
at bootstrap_node.js:607:3
Thank you.
[edit]
By using .catch(err=>{}) instead of .error(err=>{}) the bug seems to go away.
Works as expected:
var Promise = require('bluebird');
test();
async function test() {
await rejection().catch(err=>{
console.error(err);
});
}
function rejection() {
return new Promise((resolve, reject)=>{
reject(new Error('test'));
}).catch(err=>{
console.error(err);
return err;
})
}
@danielesegato Can you possibly simplify your example without all the jasmine-specific stuff? It's hard to reason through if you don't know jasmine.
I just fixed another similar bug with #1489 and I'm wondering if this issue might be related - maybe I can help, but at present I can't really work out what's going on in your example.
I've found rather similar behavior and had reported it at https://github.com/chaijs/chai/issues/1134. Will try the new code on your PR.
those changes did not resolve my particular issue.
@Celadora The issue you raise is not a bug, it's intended behaviour.
.error()
catches only operational errors, and the error you're rejecting with is not an operational error, so the .error()
handler is not invoked. So it is indeed an unhandled rejection.
.catch()
catches all errors, which is why it behaves as you expected.
This is unrelated to original issue raised by @danielesegato.
@erikerikson's issue is also unrelated to @danielesegato's original issue. @erikerikson's issue is explored in #1501.
@overlookmotel sorry I forgot to answer you, I don't know how to reproduce the problem in a simpler way cause I do not understand exactly what is causing it.
I "solved" it by forcing the use of version 3.5.0
. The warnings show up if I upgrade to 3.5.1
.
I didn't try more recent versions.
Sorry I can't be more helpful.
I can explain what my code does in respect to the Promise.
spyOn(actionHandler, 'validateActionConfig').and.returnValue(Promise.reject(new Error('dummy')));
this create a new rejection promise with an error: Promise.reject(new Error('dummy')))
and make it so a call to actionHandler.validateActionConfig()
will return that promise.
Inside sut.createAction(principal, action)
the code perform that call, which then return the rejection promise which is handled:
.catch((err) => {
expect(actionHandler.validateActionConfig).toHaveBeenCalled();
expect(err.message).toBe('dummy');
});
this part of code receive the error I created above and check the function actionHandler.validateActionConfig()
has been called and the error is the one I created above.
So, i know for sure, that function has been called and that promise has been returned.
In other words, I've handled the error and I don't expect to receive any warning like that.
I should also add this is not an ON/OFF problem, the warning doesn't always show for the same tests, it seems random and could happen in any of those test using a Promise.reject()
. And I'm 100% positive all those DO catch that exception.
If you think it is useful I can try to show you an example of the code inside that createAction
but you can think of it as something like:
this.createAction = function() {
return actionHandler.validateActionConfig();
}
In reality it's all inside a Promise.try()
with some other methods and checks but it DO return that promise cause the test pass.
Hi @danielesegato.
Thanks for replies. Just so you understand, I'm not a maintainer of bluebird, just this has got me interested. I'd like to help, but it's not crucial to my work so I can't spend too much time on it.
I don't know Jasmine, and there's a lot of moving parts in this. Being an intermittent fault will also make it even harder to diagnose.
I think only way I can help is if you're able to create a standalone repo with all the elements in place (failing test, the code for actionHandler
, and package.json with the required dependencies) - something I can clone to my computer and run to reproduce the problem. Then I may be able to figure out what's going on and fix it.
I understand if you don't have time for that, but in that case I'm afraid this is likely to remain a mystery!
@danielesegato I came up against this same issue in my Jasmine test
I fixed it by using andCallFake
instead of returnValue
spyOn(actionHandler, 'validateActionConfig').and.callFake(() => Promise.reject(new Error('dummy')));
My thought is that returnValue
immediately evaluates the result, so Node thinks your test case is rejecting a promise.
@danielesegato I came up against this same issue in my Jasmine test
I fixed it by using
andCallFake
instead ofreturnValue
spyOn(actionHandler, 'validateActionConfig').and.callFake(() => Promise.reject(new Error('dummy')));
My thought is that
returnValue
immediately evaluates the result, so Node thinks your test case is rejecting a promise.
This worked for me in an angular test using $q.reject
. Still don't understand why, its never happened before. And the only thing I can see that's different is that the promise is being used by $timeout
. I am calling .catch
appropriately as well on the promise returned from $timeout
and the one returned by the function passed into it.
3.5.1 updated the unhandled rejection to use setTimeout to delay checking if there are unhandled rejections. The functionality of setTimeout has been hijacked by the test framework hence the callback runs earlier than expected.
@petkaantonov I don't think this is for us to fix to be honest - this is something the test framework should take care of.
Ideas for how welcome by the way (I help maintain lolex which is likely the fake timers library)
I've this weird issue with jasmine testing framework and bluebird: it sometimes (not consistently) produce errors in the console log like this one:
Those are actually printed in the logs but do not make the test fail. In fact the test succeed, a test exhibiting the issue may look something like this:
The
spyOn
is jasmine way of testing mocked dependencies.sut
is the subject under test. This test check our functioncreateAction
forward any rejectiong error from the call toactionHandler.validateActionConfig()
by returning a rejection promise when the function is called. That promise is then catched, as you can see, and we also check the error is exactly the one throw there. So the promise IS catched, but somehow it is detected as uncatched.Furthermore this is not an on/off problem. Some test randomly exhibit this behavior, some never do.
This didn't happen with bluebird 3.5.0 and, according to your 3.5.1 release note (https://github.com/petkaantonov/bluebird/releases/tag/v3.5.1) you changed something in the Unhandled Promise rejection. Can you shed some light on what's possibly going on? Thanks!
related dependencies
and...
I initially posted this as a comment to an old issue here https://github.com/petkaantonov/bluebird/issues/493 and opened a bug to jasmine here: https://github.com/jasmine/jasmine-npm/issues/124
But after some further testing with different versions of jasmine and bluebird I'm fairly certain this is introduced by a change in bluebird.
The problem DID NOT happen on bluebird version 3.5.0. And I think this problem is related to https://github.com/petkaantonov/bluebird/issues/1404