Dmitri Sasov
Dmitri Sasov

Reputation: 113

Protractor: 'wait' doesn't work with "element.all"

I write Protractor automation tests and faced an issue. Wait command doesn't actually wait for one of the array elements. See the example below: I try to wait for the first element after navigating to webpage.

var category = element.all(by.repeater('category in listCtrl.categories'));
var category2 = $$('.category-name.custom-tooltip-link.ng-binding');
var EC = protractor.ExpectedConditions;

describe('wait for the first category', function() {

    it('wait', function() {
        browser.get('http://www.deep.mg/');

        browser.wait(EC.visibilityOf(category.get(0)), 20000);

        browser.wait(EC.visibilityOf(category2.get(0)), 20000);
    });
});

But test fails with the following error: Failed: Index out of bound. Trying to access element at index: 0, but there are only 0 elements that match locator by.repeater("category in listCtrl.categories").

Error doesn't depend on locator type, because appears for both: "by.repeater" and "by.css". The selectors are ok, test passes after adding 'sleep' command:

var category = element.all(by.repeater('category in listCtrl.categories'));
var category2 = $$('.category-name.custom-tooltip-link.ng-binding');
var EC = protractor.ExpectedConditions;

describe('wait for the first category', function() {

    it('wait', function() {
        browser.get('http://www.deep.mg/');

        browser.sleep(15000);

        browser.wait(EC.visibilityOf(category.get(0)), 20000);

        browser.wait(EC.visibilityOf(category2.get(0)), 20000);

        category.count().then(function(count1) {
            console.log(count1);  //count returns 5, which means there are actually elements in array
        });

        category2.count().then(function(count2) {
            console.log(count2);
        });
    });
});

Also timeout parameter doesn't help, it just ignores it and fails immediately.

So the question is how to wait for a certain element of an array? Am I missing something? Thanks.

Upvotes: 9

Views: 4579

Answers (2)

martin770
martin770

Reputation: 1288

element.all(by.repeater('category in listCtrl.categories')).get(0) will ALWAYS throw an error if there are no elements to 'get' (source: element.js ElementArrayFinder.prototype.get)

You can do:

browser.wait(function() {
    return category.count().then(function(catCount) {
        if (catCount > 0) {
            return EC.visibilityOf(category.get(0));
        }
    }
}, 20000);

Or you could probably just wait until all the elements are visible, and it would do what you are asking it to do (because it will wait for the 'all' promise to resolve completely anyway, not just break out when it gets the first one):

browser.wait(EC.visibilityOf(category), 20000);

Upvotes: 2

alecxe
alecxe

Reputation: 473823

Make a custom Expected Condition to wait for count of elements in an array to be more than 0:

function presenceOfAll(elementArrayFinder) {
    return function () {
        return elementArrayFinder.count(function (count) {
            return count > 0;
        });
    };
}

Usage:

browser.wait(presenceOfAll(category), 10000);
browser.wait(presenceOfAll(category2), 10000);

Works for me.

Upvotes: 10

Related Questions