Reputation: 4383
Is there a way to implement loops so that the following code can be reduced?
var navItems = element.all(by.repeater('item in mc.navItems'));
expect(navItems.count()).toEqual(4);
expect(navItems.get(0).getText()).toEqual('page1'.toUpperCase());
navItems.get(0).click();
expect(browser.getLocationAbsUrl()).toEqual('/page1');
expect(navItems.get(1).getText()).toEqual('page2'.toUpperCase());
navItems.get(1).click();
expect(browser.getLocationAbsUrl()).toEqual('/page2');
expect(navItems.get(2).getText()).toEqual('page3'.toUpperCase());
navItems.get(2).click();
expect(browser.getLocationAbsUrl()).toEqual('/page3');
expect(navItems.get(3).getText()).toEqual('page4'.toUpperCase());
navItems.get(3).click();
expect(browser.getLocationAbsUrl()).toEqual('/page4');
I've tried multiple ways but they all fail because I'm not sure how to get them to wait until the promised value is returned.
Here's one way that fails:
var navItems = element.all(by.repeater('item in mc.navItems'));
for(var i = 0; i < navItems.count(); i++) {
expect(navItems.get(i).getText()).toEqual(expectedValue[i].toUpperCase());
navItems.get(i).click();
expect(browser.getLocationAbsUrl()).toEqual('/' + expectedValue[i]);
}
where expectedValue = ['page1', 'page2', 'page3', 'page4'];
The problem with this is that the for loop evaluates the condition even before the promised value is returned and so the contents of the loop are never executed.
I'm sure I can use a then
and attach a callback function to count()
but that would only make things messy because I'd have to make navItems
a global variable so that it can be accessed by the callback function and I also need to make sure that navItems
is populated before the callback function is executed.
I'm aware that the expect()
method takes care of promises in a nice clean way, I would like to implement something like this.
Upvotes: 2
Views: 5217
Reputation: 299
Step 1 : first get the list of elements
let listOfElements = element.all(by.repeater('item in mc.navItems'));
Step 2: Iterate the element using below line
listOfElements.each(function (element, index) {
element.getText().then(function (text) {
console.log(index, text);
});
});
Upvotes: 0
Reputation: 2092
I don't know if the each()
method was available at the time this question was asked, but these days I'm pretty sure each()
is the best approach.
In the stated context, the answer would look something like:
var navItems = element.all(by.repeater('item in mc.navItems'));
navItems.each((element, index) => {
expect(element.getText()).toEqual(('page'+index).toUpperCase());
element.click();
expect(browser.getLocationAbsUrl()).toEqual('/page'+index);
});
Much better than calling out each element individually!
Upvotes: 2
Reputation: 736
I think the problem that you have is not with the delay in return of promise but with closure. Take a look here-Using protractor with loops
You can also use a recursion loop with if
instead of using for
as it is simpler-
function loop(i){
if(i>=navItems.count())
{
return null;
}
else
{
expect(navItems.get(i).getText()).toEqual(expectedValue[i].toUpperCase());
navItems.get(i).click();
expectations.push(expect(browser.getLocationAbsUrl()).toEqual('/' + expectedValue[i]));
})
return loop(i+1)
}
}return loop(navItems.count());
Upvotes: 0
Reputation: 8465
I'm using protractor with cucumber and what I do is something like this
element.all(by.repeater('item in mc.navItems')).then(function (elements) {
navItems = elements
var expectations = []
for (var i = 0; i < navItems.count(); i++) {
expect(navItems.get(i).getText()).toEqual(expectedValue[i].toUpperCase());
navItems.get(i).click();
expectations.push(expect(browser.getLocationAbsUrl()).toEqual('/' + expectedValue[i]));
}
Q.all(expectations).should.notify(callback)
})
so the test will wait for all expectations to execute before notifying callback
Upvotes: 4