Need help on try-catch - javascript

I am trying to use try-catch block in my protractor test, please see the code below:
try {
element(by.id('usernameas')).sendKeys(data);
}
catch(err) {
console.log('error occured');
}
I am deliberately passing wrong locator to check whether it is going in catch block or not, currently it is giving me error NoSuchElementError on command prompt and test execution stops rather than going into catch block.
Please suggest.

The call to element(locator).sendKeys returns a promise which is either resolved or rejected. The promise is part of the test's control flow.
The call to element(locator) itself does not throw an error, it is the promise which is rejected.
If you fail to find an element you actually want your entire test to fail, since the scneario cannot be completed.
To get the error message you can use the promise callbacks, as demonstrated below.
Important note: if you handle the promise failure by yourself your test won't fail, so you should better rethrow it
try {
element(by.id('usernameas')).sendKeys(data).then(function() {
console.log('keys sent successfully');
}, function(err) {
console.error('error sending keys ' + err);
throw err;
});
}
catch(err) {
console.log('error occured');
}
The console output is (trimmed):
error sending keys NoSuchElementError: no such element
(Session info: chrome=31.0.1650.63)
(Driver info: chromedriver=2.8.241075,platform=Windows NT 6.1 S .....

I ran into this problem recently and noticed that you DONT need the try/catch block. In Protractor, you can achieve the try/catch like following:
try { <---------------------------- Traditional TRY/CATCH method
loadWebApp();
login();
openUserPreferences();
changePassword();
} catch (err) {
console.error(
"An error was thrown! " + err);
}
loadWebApp().
then(login).
then(openUserPreferences).
then(changePassword).
then(null, function(err) { <----------------- PROTRACTOR equivalent of try/catch
console.error(
"An error was thrown! " + err);
});
Here's the source where I got this info from: https://code.google.com/p/selenium/wiki/WebDriverJs#Promises
under Value Propagation and Chaining
So again, you don't need to explicitly add a try/catch.
In short, the reason this method works is because a promise can either be RESOLVED or REJECTED and in case of a rejected or failed promise, this line [ then(null, function(err) { ... } ] will act as the CATCH block. Also notice that the then(null, function(err))( is NOT taking any callback but only an errBack; so basically, this is saying we don't care about whether the promise gets resolved, we only care about whether it fails and thus the NULL for callback and the function(error) for the errBack. No need to wrap this in a try/catch then throw the error as suggested above by the accepted answer (#Eitan Peer). Hope this helps someone out there struggling with Protractor as I did.

Related

How can I throw an error from within a catch, without it being an UnhandledPromiseRejection

if I just throw a random error, my code works fine:
throw new Error('you got error')
but if I want to throw it from within a .catch statement, like so:
message.react(e).catch(()=>{throw new Error('you got error')});
Then I get the error gets logged like so: (node:21609) UnhandledPromiseRejectionWarning: Error: you got error, and doesn't get caught by my higher up error handler:
//errors from within catch() don't reach this
process.on('uncaughtException', function(err){ console.log('error caught', err); });
I don't want to use promises, but unfortunately this is from an lib where i don't have a choice.
How can I throw the exception from within the catch in a way that it's not an Unhandled Promise Rejection?
If you're just trying to log unhandled promise rejections for diagnostic purposes, you can do that with:
process.on('unhandledRejection', (reason, promise) => {
console.log('Unhandled Rejection at:', promise, 'reason:', reason);
// Application specific logging, throwing an error, or other logic here
});
See doc here.
As I have said before, this should not be how you actually handle promise rejections. They should be caught in your own code at a lower level where you have the precise context for the particular operation that created the error. This code should be for diagnostic debugging only where you then go and fix the actual code that wasn't handling the promise rejection where it is supposed to be handled.

If a promise is fine to be rejected, then how should we handle it or just not even handle it or catch it?

If there are situations where it is fine for a promise to be rejected, due to this rejection, an error is still thrown. How should we handle it or just ignore it?
Case 1: If the user can click a cancel button and an operation is canceled and we consider such cancelation is fine, do we just handle it by:
p.then(value => {
// fulfillment handler
}, err => {}); // do nothing
or
p.then((value) => {
// fulfillment handler
}).catch(err => {}); // do nothing
Or can we just totally ignore it and not use a rejection handler or catch()?
Case 2: What if we do a
let p = Promise.reject(1);
then an exception is immediately thrown. There is no time to even catch it. Then must we always use:
let p = Promise.reject(1).catch(err => {});
? Actually, if p above is printed, it is a resolved promise, while the one without the catch() is a rejected promise, so I am a bit confused. I thought both should be in a rejected state.
If you use a promise rejection/exception to signal that something was cancelled, it makes sense to catch this error.
But, an important rule of thumb is that if you catch an error and you expect a certain error to be thrown (CancellationError for example), you should make sure in your catch clause that it's specifically an error of that type.
Otherwise you run the risk of some other exception being thrown and silently eaten up by your (empty) catch handler.
So I would usually expect this to look something like this:
try {
await someOperation();
} catch (err) {
if (!(err instanceof Cancellation)) {
// Re-throw
throw err;
}
console.log('Operation cancelled');
}

How to throw an exception in the Promise catch method in JavaScript? [duplicate]

Why can't I just throw an Error inside the catch callback and let the process handle the error as if it were in any other scope?
If I don't do console.log(err) nothing gets printed out and I know nothing about what happened. The process just ends...
Example:
function do1() {
return new Promise(function(resolve, reject) {
throw new Error('do1');
setTimeout(resolve, 1000)
});
}
function do2() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
reject(new Error('do2'));
}, 1000)
});
}
do1().then(do2).catch(function(err) {
//console.log(err.stack); // This is the only way to see the stack
throw err; // This does nothing
});
If callbacks get executed in the main thread, why does the Error get swallowed by a black hole?
As others have explained, the "black hole" is because throwing inside a .catch continues the chain with a rejected promise, and you have no more catches, leading to an unterminated chain, which swallows errors (bad!)
Add one more catch to see what's happening:
do1().then(do2).catch(function(err) {
//console.log(err.stack); // This is the only way to see the stack
throw err; // Where does this go?
}).catch(function(err) {
console.log(err.stack); // It goes here!
});
A catch in the middle of a chain is useful when you want the chain to proceed in spite of a failed step, but a re-throw is useful to continue failing after doing things like logging of information or cleanup steps, perhaps even altering which error is thrown.
Trick
To make the error show up as an error in the web console, as you originally intended, I use this trick:
.catch(function(err) { setTimeout(function() { throw err; }); });
Even the line numbers survive, so the link in web console takes me straight to the file and line where the (original) error happened.
Why it works
Any exception in a function called as a promise fulfillment or rejection handler gets automatically converted to a rejection of the promise you're supposed to return. The promise code that calls your function takes care of this.
A function called by setTimeout on the other hand, always runs from JavaScript stable state, i.e. it runs in a new cycle in the JavaScript event loop. Exceptions there aren't caught by anything, and make it to the web console. Since err holds all the information about the error, including the original stack, file and line number, it still gets reported correctly.
Important things to understand here
Both the then and catch functions return new promise objects.
Either throwing or explicitly rejecting, will move the current promise to the rejected state.
Since then and catch return new promise objects, they can be chained.
If you throw or reject inside a promise handler (then or catch), it will be handled in the next rejection handler down the chaining path.
As mentioned by jfriend00, the then and catch handlers are not executed synchronously. When a handler throws, it will come to an end immediately. So, the stack will be unwound and the exception would be lost. That is why throwing an exception rejects the current promise.
In your case, you are rejecting inside do1 by throwing an Error object. Now, the current promise will be in rejected state and the control will be transferred to the next handler, which is then in our case.
Since the then handler doesn't have a rejection handler, the do2 will not be executed at all. You can confirm this by using console.log inside it. Since the current promise doesn't have a rejection handler, it will also be rejected with the rejection value from the previous promise and the control will be transferred to the next handler which is catch.
As catch is a rejection handler, when you do console.log(err.stack); inside it, you are able to see the error stack trace. Now, you are throwing an Error object from it so the promise returned by catch will also be in rejected state.
Since you have not attached any rejection handler to the catch, you are not able to observe the rejection.
You can split the chain and understand this better, like this
var promise = do1().then(do2);
var promise1 = promise.catch(function (err) {
console.log("Promise", promise);
throw err;
});
promise1.catch(function (err) {
console.log("Promise1", promise1);
});
The output you will get will be something like
Promise Promise { <rejected> [Error: do1] }
Promise1 Promise { <rejected> [Error: do1] }
Inside the catch handler 1, you are getting the value of promise object as rejected.
Same way, the promise returned by the catch handler 1, is also rejected with the same error with which the promise was rejected and we are observing it in the second catch handler.
I tried the setTimeout() method detailed above...
.catch(function(err) { setTimeout(function() { throw err; }); });
Annoyingly, I found this to be completely untestable. Because it's throwing an asynchronous error, you can't wrap it inside a try/catch statement, because the catch will have stopped listening by the time error is thrown.
I reverted to just using a listener which worked perfectly and, because it's how JavaScript is meant to be used, was highly testable.
return new Promise((resolve, reject) => {
reject("err");
}).catch(err => {
this.emit("uncaughtException", err);
/* Throw so the promise is still rejected for testing */
throw err;
});
According the spec (see 3.III.d):
d. If calling then throws an exception e,
a. If resolvePromise or rejectPromise have been called, ignore it.
b. Otherwise, reject promise with e as the reason.
That means that if you throw exception in then function, it will be caught and your promise will be rejected. catch don't make a sense here, it is just shortcut to .then(null, function() {})
I guess you want to log unhandled rejections in your code. Most promises libraries fires a unhandledRejection for it. Here is relevant gist with discussion about it.
Yes promises swallow errors, and you can only catch them with .catch, as explained more in detail in other answers. If you are in Node.js and want to reproduce the normal throw behaviour, printing stack trace to console and exit process, you can do
...
throw new Error('My error message');
})
.catch(function (err) {
console.error(err.stack);
process.exit(0);
});
I know this is a bit late, but I came across this thread, and none of the solutions were easy to implement for me, so I came up with my own:
I added a little helper function which returns a promise, like so:
function throw_promise_error (error) {
return new Promise(function (resolve, reject){
reject(error)
})
}
Then, if I have a specific place in any of my promise chain where I want to throw an error (and reject the promise), I simply return from the above function with my constructed error, like so:
}).then(function (input) {
if (input === null) {
let err = {code: 400, reason: 'input provided is null'}
return throw_promise_error(err)
} else {
return noterrorpromise...
}
}).then(...).catch(function (error) {
res.status(error.code).send(error.reason);
})
This way I am in control of throwing extra errors from inside the promise-chain. If you want to also handle 'normal' promise errors, you would expand your catch to treat the 'self-thrown' errors separately.
Hope this helps, it is my first stackoverflow answer!
Listen for unhandled errors:
window.addEventListener('unhandledrejection', e => {
// ...
});
window.addEventListener('error', e => {
// ...
});
If error gets swallowed, use self.report(error):
.catch(error => {
self.reportError(error);
});
https://developer.mozilla.org/en-US/docs/Web/API/reportError

JS bluebird promise error gives no detail

I'm using bluebird promise with Node.js, after a long piece of code Promise caught an error and when I tried to print out the error message, all it said was:
[ReferenceError: i is not defined]
Is there anything I can do to get more details of the error, like the number of line that made this happen?
While using Promise, I tend to catch error like so:
return User.findOne({
id: someId
}).then(function(foundUser) {
// do something
}).catch(function(err) {
console.log(err);
});
If I just remove the catch mechanism, Node.js will print out all the error stack trace for me...

does promise catch too much errors?

I am writing promise following this style in the doc:
Q.fcall(promisedStep1)
.then(promisedStep2)
.then(promisedStep3)
.then(promisedStep4)
.then(function (value4) {
// Do something with value4
})
.catch(function (error) {
// Handle any error from all above steps
})
.done();
The catch clause will catch any errors including typos.
However, according to nodejs dos:
By the very nature of how throw works in JavaScript, there is almost never any way to safely "pick up where you left off", without leaking references, or creating some other sort of undefined brittle state. The safest way to respond to a thrown error is to shut down the process.
Some kinds of errors would throw out if we are writing code in the callback style, but not in promise style
This is really confusing me. How should I avoid leaking references when writing in promise.
Thanks~
The example shows good promise chain, including using .done() to make sure any unhandled exceptions are thrown from the promise chain to the outside application.
As far as references and error handling: the promise chains only guarantee than an error will be forwarded to the .catch callback. If there is no way to clean up the state when the error is thrown - you are out of luck. For example
Q.fncall(function firstStep() {
var fs = open file reference
foo.bar; // generates ReferenceError
}).then(function somethingElse() {
...
}).catch(function (err) {
// we have caught ReferenceError
// but we cannot clean up open fs reference!
}).done();
We caught the error, but the catch handler cannot close fs reference. This is what it means that even with promises we have to think how to clean up resources in case of an error.

Categories

Resources