1

I am doing e2e testing on a site that contains a table which I need to iterate "until" finding one that doesn't fail when I click on it.

I tried it using filter and it is working:

this.selectValidRow = function () {
    return Rows.filter(function (row, idx) {
        row.click();
        showRowPage.click();
        return errorMessage.isDisplayed().then(function (displayed) {
            if (!displayed) {
                rowsPage.click(); // go back to rows Page, all the rows
                return true;
            }
        });
    }).first().click();
}; 

The problem here is that it is iterating all available rows, and I only need the first one that is valid (that doesn't show an errorMessage).

The problem with my current approach is that it is taking too long, as my current table could contain hundreds of rows.

Is it possible to filter (or a different method) and stop iterating when first valid occurrence appears?, or could someone come up with a better approach?

eLRuLL
  • 18,488
  • 9
  • 73
  • 99
  • But how do you know is a valid row?, just by clicking on it and seeing there is no error? – Hosar Mar 26 '17 at 15:26
  • yes, in my case, I really need to access one of those rows page, and some of the rows give errors (because their respective pages don't exist or something). I just want a way to find one of the rows that won't give me an error. – eLRuLL Mar 26 '17 at 15:29

2 Answers2

2

If you prefer a non-protractor approach of handling this situation, I would suggest async.whilst. async is a very popular module and its highly likely that your application is using it. I wrote below code here in the editor, but it should work, you can customize it based on your needs. Hopefully you get an idea of what I'm doing here.

var found = false, count = 0;
async.whilst(function iterator() {
   return !found &&  count < Rows.length;
}, function search(callback) {
    Rows[count].click();
    showRowPage.click();
    errorMessage.isDisplayed().then(function (displayed) {
        if (!displayed) {
            rowsPage.click(); // go back to rows Page, all the rows
            found = true; //break the loop
            callback(null, Rows[count]); //all good, lets get out of here
        } else {
           count = count + 1;
           callback(null); //continue looking
        }
    });
}, function aboutToExit(err, rowIwant) {
    if(err) {
      //if search sent an error here;
    }
    if(!found) {
      //row was not found;
    }
    //otherwise as you were doing
    rowIwant.click();
});
nilesh
  • 14,131
  • 7
  • 65
  • 79
0

You are right, filter() and other built-in Protractor "functional programming" methods would not solve the "stop iterating when first valid occurrence appears" case. You need the "take some elements while some condition evaluates to true" (like the itertools.takewhile() in Python world).

Fortunately, you can extend ElementArrayFinder (preferably in onPrepare()) and add the takewhile() method:

Note that I've proposed it to be built-in, but the feature request is still open:

Community
  • 1
  • 1
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195