0

I am writing Appium (v1.7.1) iOS automation tests where I am chaining a webdriver session and trying loop through the elements to fetch the data.

setFilterOptions: function (driver, loc) {
    var chain = driver;                  //I am assigning the driver to chain
    chain = chain
         .getFilterElementListCount()    //This gives me back the count for elements
         .then((count) => {
            console.log("Number of Filters - ",count);  

            for(var i=1; i<=count; i++) {
              ((i) => {
                console.log("Value of i - ", i);
                //This gives me the label for each Cell->StaticText
                chain = chain
                      .getElAttribute('label',util.format('//XCUIElementTypeCell[%d]/XCUIElementTypeStaticText[1]', i), 'xpath')                           
                      .then((filterTitle, i) => {
                            console.log("Filter Title - ", filterTitle);
                            console.log("I value - ", i);
                      });
              })(i);
            }
         });
  return chain;
},    

The Console o/p i am getting is - 
Number of Filters -  3
Value of i -  1
Value of i -  2
Value of i -  3

The loop iterates but doesn't execute the chain within the for loop. Is there a way for the chain to finish all callback execution before returning it.

Rajiv
  • 27
  • 7

1 Answers1

0

Your goal is to return a promise that will resolve once all the work performed in the loop is done. However, that's not what you are doing. Your problem is that you have this:

  chain = chain.//
                // Bunch of asynchronous operations, some of which assign 
                // to the variable `chain`.
                //
  return chain;

In order for your code to work, the asynchronous operations would have to assign to chain before the return statement executes. But this is not how asynchronous operations work. When you call any asynchronous method, you are only scheduling the asynchronous operation for future execution. It will execute at some point in the future, but definitely not immediately. In the code you have, you schedule an asynchronous operation and the immediately you return chain. The value of chain that you return cannot be a value that is set in your loop. Your loop has not executed yet.

You should do something like the following. The important thing is to create a chain of operations inside the loop and return that chain from the function you pass to .then so that the topmost promise resolves to the chain you create in your loop. This way, the promise you return from your method will have to wait for all inner operations to be done before being resolved.

setFilterOptions: function (driver, loc) {
    return driver
         .getFilterElementListCount()    //This gives me back the count for elements
         .then((count) => {
            var chain = Promise.resolve();
            console.log("Number of Filters - ",count);  

            for(var i=1; i<=count; i++) {
              ((i) => {
                console.log("Value of i - ", i);
                //This gives me the label for each Cell->StaticText
                chain = chain
                      .getElAttribute('label',util.format('//XCUIElementTypeCell[%d]/XCUIElementTypeStaticText[1]', i), 'xpath')                           
                      .then((filterTitle, i) => {
                            console.log("Filter Title - ", filterTitle);
                            console.log("I value - ", i);
                      });
              })(i);
            }

            // Return your promise!                
            return chain;
         });
},    

Also note that if you use let i instead of var i for your loop, you could get rid of that immediately invoked arrow function you have in your loop, which seems to be there only to ensure that the closures inside the loop get sequential values of i (instead of all executing with the last value of i).

Louis
  • 146,715
  • 28
  • 274
  • 320
  • Thanks a lot for the reply! Solved the issues with your answer. Also, used **let i** in the loop and cleaned up the method. – Rajiv Nov 16 '17 at 18:21