Narco
Narco

Reputation: 13

stale element references in loop after redirection to another page

i am trying to choose a certain element of similar objects on a website, in my e2e tests, and to click it then to change to another site, related to that element. The Problem is that the loop is still going on after the page is changed because the promise resolves asynchronous (i'm new to all this stuff)

Here the code:

    goToCartridge(name){
    let done = false;
    element(by.id('dashboard')).all(by.className('card z-depth-1')).then( elems => {
      for(let i = 0; i < elems.length ; i++ ){
        if(done) break;
          elems[i].element(by.tagName('h2')).getText().then( text => {
            if(name === text) {
              element(by.id('cartridge-' + i)).click();
              done = true;
            }
          return;
        });
      }
    });
  }

How can i wait for the async part inside the loop before the next iteration starts? i searched alot for a solution, but couldnt find one yet.

Upvotes: 1

Views: 92

Answers (3)

Xotabu4
Xotabu4

Reputation: 3091

I would suggest to rewrite to something like this:

goToCartridge(name) {
    $$('#dashboard .card.z-depth-1 h2').each((card, index) => {
        card.getText().then(text=> {
            if (name === text) {
                $(`cartridge-${index}`).click()
            }
        })
    })
}

Upvotes: 1

HMR
HMR

Reputation: 39260

Maybe this works, I changed the for loops to array.map and filter. Not sure if Array.from is going to work on elms:

goToCartridge(name){
  element(by.id('dashboard')).all(by.className('card z-depth-1'))
  .then( 
    elems => {
      Promise.all(
        Array.from(elems).map(
          element =>
            element.element(by.tagName('h2')).getText()
            .then( text => [text,element] )
        )
      ).then(
        result=> {
          let [_,index] = result.map(
            ([text,element],index)=>[name === text,index]
          ).filter(
            ([hasText,index])=>hasText
          )[0];
          if(index !== undefined){
            return element(by.id('cartridge-' + index)).click();
          }
          else{
            return Promise.reject("could not find element");
          }
        }
      )
    }
  });
}

Upvotes: 0

Nizar Ahmed
Nizar Ahmed

Reputation: 180

u can skip the loop of elems and call check next element of elems from inside gettext() callback like this

goToCartridge(name){
    let done = false;
    element(by.id('dashboard')).all(by.className('card z-depth-1')).then( elems => {
    function check(i) {
      if( i >= elems.length ) return;
      elems[i].element(by.tagName('h2')).getText().then( text => {
        if(name === text) {
          element(by.id('cartridge-' + i)).click();
        }
        else {
          check(i+1);
        }
      });
    }
    check(0);
  });
}

Upvotes: 1

Related Questions