How to ensure first iteration of a loop is finished before executing second iteration?

Viewed 138
cy.document().then(document => {
  const arra = [...document.querySelectorAll('.instances__action')];

  for (let i = 1; i <= arra.length; i++) {
    let state = document.querySelector(
      `#root > section > section > main > div > div > section.instances > div > div > div > div > div > div > table > tbody > tr:nth-child(${i}) > td:nth-child(3) > span`
    ).innerText;

    if (state !== 'Finished') {
      document
        .querySelector(
          `#root > section > section > main > div > div > section.instances > div > div > div > div > div > div > table > tbody > tr:nth-child(${i}) > td:nth-child(7) > div > button.ant-btn.ant-btn-primary.ant-btn-sm`
        )
        .click();
    } else {
      continue;
    }
  }
});

here, suppose the arra.length is 2. on each iteration button is clicked. I want to do it one at a time. At first, it should check if the state is finished or not. If the state is not finished it should press the button and wait until the state becomes finished. After that, it should go to the next iteration. In my current implementation, It goes to the second iteration before the first iteration is finished.

1 Answers

At the section of the code that sets the text to Finished, have it call the resolve function of a Promise constructor which is assigned to in the loop. Then, in the loop, construct the Promise and await it. For example:

let resolveFn = () => undefined;

// ...
// Run loop:
(async () => {
  // ...
  for ( // ...
  // ...
    if (state !== 'Finished') {
      const prom = new Promise(resolve => resolveFn = resolve);
      document.querySelector(...).click();
      await prom;
    }
}
})();

// ...

function clickHandler() {
  // ...
  // At the point where you assign "Finished", call the resolveFn:
  span.textContent = 'Finished';
  resolveFn();
}

If you don't have control over the code that assigns the Finished text, the other possibility to watch for the change of the text would be to use a MutationObserver, eg:

if (state !== 'Finished') {
  document.querySelector(...);.click();
  await new Promise((resolve) => {
    new MutationObserver((_, observer) => {
      if (span.textContent === 'Finished') {
        observer.disconnect();
        resolve();
      }
    })
      .observe(span, { childList: true });
  });
}
Related