1

I have a Puppeteer script that logs into a website and then is looking to click on 7 different "Add Time" buttons within an iFrame. Since the IDs change dynamically, I have it looking for the text of the button.

I have it logging in correctly and able to click sometimes, but it doesn't click all the buttons. It isn't consistent either, the last two buttons may click or the second button.

Here is the code:

let test = await frame.$$('[type="button"]')
test.forEach(async el => {
  var text = await (await el.getProperty('textContent')).jsonValue()
  if (text == "Add Time") {
    await el.click();
  }
});
ggorlen
  • 44,755
  • 7
  • 76
  • 106

1 Answers1

2

As mentioned in the comments, the following pattern runs all of the clicks simultaneously:

test.forEach(async el => {...});

Most websites aren't usually designed such that 7 different clicks should occur at nearly the same time--it's inhuman. Often, there is some loading animation or pause before it makes sense for the user to click again.

Another issue with the above pattern is any code you have after this will be in a different promise chain and won't be able to wait for the results of these clicks. You'd have to use await Promise.all([test.map(async el => {...})]) to make that happen.

As OP confirmed in the comments, the typical solution is sequential iteration:

for (const el of test) {
  ...
}

This runs each click fully to completion, then the next one only after the last one has finished. Code after the for loop will execute after all iterations of the loop have completed.

See Crawling multiple URLs in a loop using Puppeteer and Using async/await with a forEach loop.

ggorlen
  • 44,755
  • 7
  • 76
  • 106