Jags
Jags

Reputation: 111

Looping events with Protractor automation framework

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

Answers (2)

craig
craig

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

Brine
Brine

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

Related Questions