assert.throws says => Missing expected exception - node.js

I am using this chunk of code:
assert.throws(async () => {
patientSubscriber = await PatientSubscriber.create({
isSubscribed: true,
patient: patient._id,
subscriber: user._id
});
},{
message: /foo/
});
when I run it I get this:
AssertionError [ERR_ASSERTION]: Missing expected exception.
The assert API is:
https://nodejs.org/api/assert.html#assert_assert_throws_fn_error_message
Maybe I am hitting this issue?
https://github.com/nodejs/node-v0.x-archive/issues/8368
Anyone know what that error is about?

The error means that there was no exception while it was expected. async functions are syntactic sugar for promises. They never throw exceptions but may return rejected promise.
Since the assertion is expected to be synchronous, it's impossible to assert promises this way; the entire callstack should be promise-based.
As it was mentioned in comments, assert.rejects appeared in Node 10 and results in rejected promise on assertion fail.
In case promises are handled by a caller (e.g. in most testing frameworks), rejected promise needs to be returned from current function:
it('...', async () {
await assert.rejects((async () => {})()); // current function returns rejected promise
});
In case assertion promises aren't handled (e.g. in production), they result in UnhandledPromiseRejectionWarning console output, not in exceptions. unhandledRejection handler can be set to handle asynchronous errors:
process.on('unhandledRejection', err => {
console.error(err);
process.exit(1);
});
...
assert.rejects((async () => {})());

Related

Why promise reject does not handle an error

I'm using nodejs request package (2.88 version) with node v10.24.1
The Promise below does not handle an error if the url simply was not specified. I'm getting UnhandledPromiseRejectionWarning and from the request package source I can see an exception thrown for that case.
If I remove the async keyword everything works fine, and the reject handled.
return new Promise(async (resolve, reject) => {
request(uri: url).on('error', err => {
reject();
}).on('response', response => {
resolve();
});
});
Could you please explain what happens. Probably the request's exception finished before the reject actually fired. Any details please.
When you pass a function to new Promise, this function gets immediately executed.
There's no magic here, for the purpose of illustration, the constructor of new Promise() might look a bit like this:
class Promise {
constructor(executor) {
executor(this.resolveFunction, this.rejectFunction);
}
}
So this example:
new Promise(() => {
console.log(1);
});
console.log(2);
Outputs:
1
2
This is important, because if you pass something to new Promise that throws an exception, this happens immediately too:
new Promise((res, rej) => {
throw new Error('foo');
});
The error thrown here doesn't cause the promise to be rejected, it completely prevents new Promise() from succeeding. No promise is returned, and the exception is thrown in the outer function that called new Promise().
However, this breaks down when you pass an async function:
new Promise(async (res, rej) => {
throw new Error('foo');
});
Because of how async functions work, this error will not be thrown during the setup of new Promise(), but the async function you passed will handle the error asyncronously and returns a rejected promise, that new Promise() doesn't know how to handle.
This is no different from calling an async function directly yourself and not handling errors:
(async () => {
throw new Error('foo');
})();
So the reason things are failing have less to do with new Promise(), but more with the fact how async functions work in general.
Just a last time for future readers, you should never pass an async executor to new Promise(), because:
The only reason you need async at all is so you can use await.
await only works with promises.
If you already had a promise you wanted to await, you didn't need new Promise() to begin with, because the main use-case of new Promise is to convert something that doesnt use promises into something that does.

Node.js Promise without returning it

I have a use case to resolve a Promise without returning it. Catching for errors internally, but don't want the caller to wait for the promise to resolve.
doSomething()
{
Promise.resolve()
.then(() => {
// do something.
})
.catch(reason => {
this.logger.error(reason);
});
}
Getting this error:
(node:2072) Warning: a promise was created in a handler at internal/timers.js:439:21 but was not returned from it, see http://. goo.gl/rRqMUw
at Function.Promise.cast (.../node_modules/bluebird/js/release/promise.js:225:13)
Just return something from the Promise callback where you are creating the fire and forget promise.
I'm guessing that handler is doSomething
doSomething()
{
Promise.resolve()
.then(() => {
// do something.
})
.catch(reason => {
this.logger.error(reason);
});
return null //or anything else that's sensible
}
Note: We usually ignore the error message, but sometimes they contain valuable information. In your error there's a link http://. goo.gl/rRqMUw that explains exactly this problem:d

caching promises leads to Unhandled promise rejection in Node.js

using nodejs v. 7.5.0 I'm getting
UnhandledPromiseRejectionWarning && DeprecationWarning
I know its part of new features since node 6.6 but the thing I don't understand is that I'm catching that promises just after caching it into a variable. If I don't cache it no warning is thrown.
this is the code that throws the error:
let verifyPromise = verifyToken(id_token);
verifyPromise.catch((err) => {
log(err);
});
let verifyOkPromise = verifyPromise.then((login) => {
return DB_API.getTokenById(id_token);;
});
verifyOkPromise.catch((err) => {
log('error in finding token: ', err);
});
verifyOkPromise.then((dbRes) => {
log('loggin res in finding token: ', dbRes);
});
where verifyToken() is a function that checks google auth token and returns a promise.
node output is the following:
error in finding token: { CouchbaseError message: 'The key does not exist on the server', code: 13 }
(node:10961) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): CouchbaseError: The key does not exist on the server
(node:10961) 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.
as you can see the promise error branch is regularly catched as it logs as expected but I still get the warning!!!!
while if I just append the catch like this:
verifyPromise.then((login) => {
return DB_API.getTokenById(id_token);;
}).catch((err) => {
log('error in finding token: ', err);
});
NO Warning is given!!!
I think I'm missing something subtle but I don't understand what could be.
Some one have any clues?
thanks in advance
This issue is happening because it is not the original promise that ultimately fails, it is the then()! You are not storing the result of
verifyOkPromise.then((dbRes) => {
log('loggin res in finding token: ', dbRes);
});
It is the call to then() here that ultimately triggers the resolution of the Promise chain. You're trying to handle the catch from the original call, but it's the chain that fails. Here are three simplified versions of what you're trying to do. The first matches your workflow. The second matches how these are normally written (but a pattern you didn't want to use). The third rewrites your pattern to work properly but using results assigned to variables.
let Promise = require('bluebird');
function forceReject() {
return Promise.reject('deliberately failed');
}
let p = forceReject('12345');
// This will produce an Unhandled Rejection error
/*
p.then(res => { console.log('succeeded: ', res); });
p.catch(err => { console.log('failed: ', err); });
*/
// This will work but it's not the pattern you prefer
/*
p.then(res => {
console.log('succeeded: ', res);
}).catch(err => {
console.log('failed: ', err);
});
*/
// This will also work! Note the assignment of the result of p.then()...
let q = p.then(res => { console.log('succeeded: ', res); });
q.catch(err => { console.log('failed: ', err); });
You're using Node 7.5, you should consider async/await. Chad's answer is well written and correct, but here's how I'd write the code in question:
async function whateverYoureDoing(id_token) {
const token = await verifyToken(id_token);
// catch will automatically propagate.
//You can use regular try/catch and if rethrow your own custom TokenInvalidError object
const dbRes = await DB_API.getTokenById(id_token);
console.log('loggin res in finding token: ', dbRes);
}
Note: You no longer need to add .catch and log error with promises - that's the point of the unhandledRejection tracking feature :) Logging should be generally done at a top level since promises work great with exceptions anyway.

Node.js - throw exception inside ES6 promise chain

As part of an Node.js/Express API I am developing, I have built a custom error handler that lets me throw specific errors when needed e.g. BadRequest or NotFound etc.
The problem occurs when I wish to throw within a promise chain. For example:
db.doSomethingAsync().then(data => {
if(data.length === 0){
throw new errors.ResourceNotFound({ resource: "foo" });
}
});
After much reading on the topic, I see that this error will be swallowed by the promise and hence causes an unhandled Promise rejection.
I am aware I can reject however im not sure how I can then handle the specific error (rather than a catchall on reject which I dont want).
Also, to reject, would I not need to create a new promise inside of my promise chain? That feels messy.
Can anyone advise how to handle throwing a specific exception within a promise chain?
In addition to the first callback to then() which is resolve callback and recieves data, you could also provide a second callback to it which is reject callback and it recieves errors. so you could catch this specific error on the second callback of the next then:
db
.doSomethingAsync()
.then(data => {
if(data.length === 0){
throw new errors.ResourceNotFound({ resource: "foo" });
}
})
.then(massagedData => {
// work with massagedData here
}, err => {
// handle err here which is previous thrown error
// assert.ok( err instanceof errors.ResourceNotFound() )
})
.catch(err => {
// this will catch unhandled errors if any
});
then() by default returns a promise and if any of its callbacks ( whether the first or the second one ) throws an error then it returns a rejected promise and its reason will caught by next reject callback if any or by catch at the end. So you don't need to create a new promise.
See Promise.prototype.then()

Stopping the promise chain midway

I am trying to stop a promise chain midway (After a catch). So after an error occurred in the first promise the catch will catch it but I don't want the chain to continue. I'm using bluebird. How would I do this?
getRedirectedURL(url).then(function(url) {
console.log(1);
url = domainCleanse(url);
sql = mysql.format(select, url);
return [ url, mysqlQuery(sql) ];
}).catch(function(error) {
console.log(2);
console.error(error);
socket.emit('error:unreachable', url + ' was unreachable');
}).spread(function(url, rows) {
console.log(3);
if(_.isEmpty(rows[0])) {
socketList.push({
url: url,
ttl: _.now(),
socket: socket,
added: false
});
} else {
socket.emit('done', mapResults(rows[0]));
}
}).catch(function(error) {
console.log(4);
console.error(error);
socket.emit('error', 'We could not reach ' + url + ' at this time.');
});
Generalizing your example, it looks like this:
promiseToFoo()
.then(promiseToBar)
.catch(failedToFooOrBar)
.then(promiseToFrob)
.catch(failedToFrob)
Along the happy path you are promising to Foo, then to Bar, then to Frob. Based on your description, you want to handle errors Fooing or Barring separately from errors Frobbing. So a simple solution is bury the error handling for Frob into that promise. So instead of chaining a promise to Frob, you're chaining a promise to Frob and handle errors in Frobbing. Something like this:
promiseToFoo()
.then(promiseToBar)
.catch(function (error) {
failedToFooOrBar(error);
return Promise.reject(error);
})
.then(function (x) {
return promiseToFrob(x).catch(failedToFrob);
});
A key to this is to make sure that your on-reject handler in the first catch ends up leaving the chain in a rejected state when it leaves. This is handled in the sample above by returning a rejected Promise from the handler. You can also handle it by throwing an Error from the handler. If you don't do one of these things, then the promise will be in a fulfilled state when the handler finishes and the on-fulfill handler provided by the subsequent then call will be invoked.

Resources