Reputation: 111
I am running automated test using protractor - Javascript.. where I am trying to fetch the values from UI which is in table format..
I have written script as below.. where as issue is when I go inside 'i' loop.. it is fetching all the values of 'i' rather first value of 'i' and not proceeding to 'j' loop..
However once i
loop is completed.. it is properly going to next loop j
and k
, where j
& k
loops are working as as expected (as per general looping standard in other programming languages)..
this.cate = function () {
let acct = [];
return this.getCountOfCate().then((values) => {
for (let i = 0; i < values; i++) {
openAccounts.push(browser.findElement(locators.someField).getText());
this.getRowCount().then((rowValues) => {
console.log('rowValues is' +rowValues);
for (let j = 0; j < rowValues; j++) {
this.getColumnCount().then((columnValues) => {
for (let k = 0; k < columnValues; k++) {
acct.push(element.all(classes.accountReports).all(by.css(getAccountCategoryCnt(i))).all(by.css('.title')).get(j).all(by.css('td')).get(k).getText());
}
})
}
});
}
return acct;
});
}
Above cate
is a function, it will be called from other step as promise and expect to return values in array acct
(Values are returning in this code) after returning I am comparing that with array values..
Only thing is I am not getting in right order as 'i' loop is completing all at once and then proceeding to j
and k
loop..
Please suggest what could be the issue here..
Upvotes: 0
Views: 80
Reputation: 5016
Since I have no context on what your table looks like... here's an example of using the map function for the sample HTML snippet. Promises and for loops do not work together which is why we have other methods like map
, reduce
, filter
, and each
.
HTML snippet example:
<table>
<tr>
<td class="name">Foo</td>
<td class="title">Developer</td>
</tr>
<tr>
<td class="name">Bar</td>
<td class="title">Designer</td>
</tr>
</table>
You could have a method that uses the element.all
and map
functions
// returns a promise of a list of accounts
getAccounts() => {
return element.all(by.tagName('tr')).map(elem => {
let account = new Account();
let promises = [];
let tds = elem.all(by.tagName('td'));
promises.push(tds(by.css('.name')).getText().then(text => {
account.name = text;
}));
promises.push(tds(by.css('.title')).getText().then(text => {
account.title = text;
}));
return Promise.all(promises).then(() => {
return account;
});
});
}
So to get the values, you would call:
getAccounts().then(accounts => {
console.log(accounts);
});
Upvotes: 5
Reputation: 3731
Async looping is hard. My favorite solution for this issue is an IIFE
([Instantly Invoked Function Expression][1]). Basically, you create your loop, create the iife, and pass in the index. Here's a basic example.
Here's a basic example:
describe('to loop tests', function() {
var data = ['1', '2', '3'];
for(var i = 0; i < data.length; i++) {
// create your iife
(function(i) {
it('pass in the index to an iife', function() {
console.log('i is: ' + i);
expect(data[i]).toBe(true);
});
})(i); // pass in index
}
});
That said, that many nested loops is a code smell... perhaps ask a seperate question; maybe there's a better way to accomplish what you're after.
Upvotes: 0