8

I'm trying to test a website using Puppeteer. Unfortunately, I'm having trouble clicking elements in a toolbar. The toolbar is using a CSS transition to gracefully slide into the page. My code is failing because I'm clicking where the element will appear while the page is still animating. I'm using a timeout as a workaround, but there's got to be a more elegant solution. Here's an example:

await page.click("#showMeetings"); //Toolbar slides in
await page.waitFor(3000); //Can I do this without a timeout?
await page.click("#mtgfind"); //Click button in toolbar

I think I need to wait on the transitionend event, but I'm unsure of how to do that in Puppeteer. Any help would be appreciated.

Thomas Simeroth
  • 109
  • 1
  • 4
  • I guess you use this: https://stackoverflow.com/questions/8814631/how-do-i-detect-a-transition-end-without-a-javascript-library – Asons Jul 26 '18 at 22:20
  • waitForTimeout(3000) is the current syntax. – MrE Dec 14 '21 at 18:02

3 Answers3

10

In case of Grant solution, you shouldn't forget to remove event listener and to wait for it. You can try this solution, it works for me. I had similar problem.

async waitForTransitionEnd(element) {
  await page.evaluate((element) => {
    return new Promise((resolve) => {
      const transition = document.querySelector(element);
      const onEnd = function () {
        transition.removeEventListener('transitionend', onEnd);
        resolve();
      };
      transition.addEventListener('transitionend', onEnd);
    });
  }, element);
}

And call it:

await page.click('#showMeetings');
await waitForTransitionEnd('#elementWithTransition');
await page.click("#mtgfind");
2

I came up with a fairly dumb solution. I looked up how long the transition was supposed to take (in this case 0.2 seconds) and just modified the waitFor statement to wait that long. Final code:

await page.click("#showMeetings"); //Toolbar slides in
await page.waitFor(200);
await page.click("#mtgfind"); //Click button in toolbar

This wouldn't work if the timing was variable, but the website reuses the same transition everywhere, so it's fine for my use case.

Thomas Simeroth
  • 109
  • 1
  • 4
1

You can use page.evaluate() to and the transitionend event to accomplish your goal:

await page.evaluate(() => {
  const show_meetings = document.getElementById('showMeetings');
  const mtg_find = document.getElementById('mtgfind');

  mtg_find.addEventListener('transitionend', event => {
    mtg_find.click();
  }, false);

  show_meetings.click();
});
Grant Miller
  • 27,532
  • 16
  • 147
  • 165
  • I tried implementing your solution, but wasn't able to get it to work. The eventListener never fired, which meant that the search button was never clicked. Not sure why it didn't work though. – Thomas Simeroth Jul 27 '18 at 21:11