Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rejected promises in Protractor/WebDriverJS

WebDriverJS and Protractor itself are entirely based on the concept of promises:

WebDriverJS (and thus, Protractor) APIs are entirely asynchronous. All functions return promises. WebDriverJS maintains a queue of pending promises, called the control flow, to keep execution organized.

And, according to the definition:

A promise is an object that represents a value, or the eventual computation of a value. Every promise starts in a pending state and may either be successfully resolved with a value or it may be rejected to designate an error.

The last part about the promise rejection is something I don't entirely understand and haven't dealt with in Protractor. A common pattern we've seen and written is using then() and providing a function for a successfully resolved promise:

element(by.css("#myid")).getAttribute("value").then(function (value) {
    // do smth with the value
});

The Question:

Is it possible that a promise returned by any of the Protractor/WebDriverJS functions would not be successfully resolved and would be rejected? Should we actually worry about it and handle it?

like image 270
alecxe Avatar asked Aug 04 '15 13:08

alecxe


2 Answers

I've experienced a use-case of promise rejection while using browser.wait(). Here is an example:

var EC = protractor.ExpectedConditions;

function isElementVisible() {

    var el = element(by.css('#myel'));

    // return promise
    return browser.wait(EC.visibilityOf(el), 1000)
    .then(function success() {
        return true; // return if promise resolved
    }, function fail() {
        return false; // return if promise rejected
    });
}

expect(isElementVisible()).toBe(true);
expect(isElementVisible()).toBe(false);

Here, if element is on a page, success will be executed, otherwise, if it is not found when 1 second passes, then fail will be called. My first point is that providing a callback for rejection gives an ability to be consistent with what one should expect. In this case I am kinda sure that promise will always resolve to true or false, so I can build a suite relying on it. If I do not provide a fail callback, then I'll get an Uncaught exception because of timeout, which will still fail my particular spec and still run the rest of the specs. It won't be uncaught by the way, Protractor is gonna catch it, but here I want to bring a second point, that Protractor is considered a tool which you use to write and run your code, and if an exception is caught by Protractor, then this exception has left your code unhandled and your code has a leak. But ... at the same time I do not think that one should waste time to catch everything in tests: if there is no element on a page or click has failed, then a respective spec will obviously fail too, which is fine in most of the cases. Unless you want to use the result of failure to build some code on top of it like it is in my sample.

like image 77
Michael Radionov Avatar answered Oct 26 '22 17:10

Michael Radionov


That is the great thing about promises you are going to get a response, either an response of data or an error message. That extended to a series of promises like Webdriver uses you are going to get an array of responses or a failure response of the first one that fails. How you handle the failed response is up to you I usually just dump it into a log for the console to see what failed. The only thing you need to figure out is do you abort the rest of your tests or do you continue on.

Here is a decent article on the subject as well. http://www.toolsqa.com/selenium-webdriver/exception-handling-selenium-webdriver/

Fyi what you are doing is fine you are just never bothering to catch any of the errors though, I am not sure if that matters to you or not, you could also abstract the call in a function to auto handle the errors for you if you wanted to log them somewhere.

like image 23
James Avatar answered Oct 26 '22 17:10

James