Vin
Vin

Reputation: 177

Protractor getting stale element reference in page object

I am verifying the filter options in a page. Every time I select an option I submit the filters then the page refreshes with the new result. Again I click on the filter button and need to select next radio button. But I am getting stale element reference error.

filterButton.click().then(function () {
  filteroptions.count().then(function (totalradios) {
    console.log("before start" + totalradios);
    filteroptions.each(function (radiooption, index) {
      radiooption.getText()  //getting error at this place on the second iteration
       .then(function (radioName) {
        console.log(radioName, index);
      })
      radiooption.click().then(() => {
        filterSubmit.click().then(function () {
          console.log(totalradios, ' ', index)
          if (index <= totalradios) {
            filterButton.click();
          }
        })
      })
    })
  })
})

Updated from each(function) to For loop

 var filteroptions = element.all(by.css("md-radio-group.ng-pristine.ng-untouched.ng-valid._md.layout-row.ng-not-empty md-radio-button")); 

filterButton.click().then(function () {
  filteroptions.count().then(function (totalradios, async) {
   console.log("before start" + totalradios);
   for (var i = 0; i < totalradios; i++) {
   console.log("recalulated true " + totalradios);
   (function (index) {
    console.log("select filter option");
    filteroptions.get(index).click();
    console.log("click submit button");
    filterSubmit.click();
    console.log("click filter button");
    filterButton.click();
    console.log("get new totalcounts");
    let setradios = filteroptions.count().then((value) => {
    return value;
   })
   console.log("recalulated totalradios" + setradios);
   totalradios = setradios;
   })(i);
  }
  })
})

Tried to read the list in a separate function

var getfiltercount = function () {
  filteroptions = element.all(by.css("md-radio-group.ng-pristine.ng-untouched.ng-valid._md.layout-row.ng-not-empty md-radio-button")); // filtertext
  return filteroptions.count().then(function (addradios) {
  console.log("addradios is " + addradios);
 })
  return addradios;
}

Upvotes: 0

Views: 360

Answers (1)

yong
yong

Reputation: 13712

Because selenium will also treat below situation as entering new page:

  • Page whole refresh, even the page url not change
  • Page partial refresh, even the page url not change

Once selenium detect entering new page, the reference of elements found on previous page are invalid, if you still use them in script, selenium will report StaleReferenceException.

To resolve this problem is simple to find the element again on new page to get the new reference for later using.

// function to test when choose yes radio button

function testYesRaidoButton() {
    // click `yes` radio button
    element(<locator of `yes` raido button>).click();
    // find how many new radio buttons will appear after choose `yes`
    element.all(<locator of sub radio buttons of `yes`>).count()

    .then(function (totalradios) {
        console.log("before start " + totalradios);

        for(var i=0;i<totalradios;i++) {

            (function(index) {

                // click one of new radio button of `yes`
                element.all(<locator of sub radio buttons of `yes`>).get(index).click();

                // click `submit` button
                element(<locator of filterSubmit>).click();

                // click `yes` radio button on `new page` again
                element(<locator of `yes` raido button>).click();

            })(i);

        }
    });
}

// function to test when choose no radio button

function testNoRadioButton() {
    // click `no` radio button
    element(<locator of `no` raido button>).click();
    // find how many new radio buttons will appear after choose `no`
    element.all(<locator of sub radio buttons of `yes`>).count()

    .then(function (totalradios) {
        console.log("before start " + totalradios);

        for(var i=0;i<totalradios;i++) {

            (function(index) {

                // click one of new radio button of `no`
                element.all(<locator of sub radio buttons of `no`>).get(index).click();

                // click `submit` button
                element(<locator of filterSubmit>).click();

                // click `no` radio button on `new page` again
                element(<locator of `no` raido button>).click();

            })(i);

        }
    }); 
}

Actually, the two function has many similar code lines, you can optimize and merge into one function to accept different parameter value to archive same purpose.

Alternative solution to archive some goal by using two loop, but not recommend to do as that, because code is hard to read and understand, pretty not friendly.

// iterate `yes` and 'no'
for (var j = 0; j < 2; j++) {

  (function(__index) {

    element.all(<locator of `yes` and `no` radio button>).get(__index).click();

    element.all(<locator of new radio buttons>).count()

    .then(function(totalradios) {
      console.log("before start " + totalradios);

      // iterate new radio buttons
      for (var i = 0; i < totalradios; i++) {

        (function(index) {

          // click one of new radio buttons
          element.all(<locator of new radio buttons>).get(index).click();

          // click `submit` button
          element(<locator of filterSubmit> ).click();

          // click `yes` or `no` radio button on `new page` again
          element.all(<locator of `yes` and `no` radio button>).get(__index).click();

        })(i);

      }
    });

  })(j)

}

Upvotes: 1

Related Questions