Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wait for transition to end in puppeteer

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.

like image 582
Thomas Simeroth Avatar asked Jul 26 '18 21:07

Thomas Simeroth


3 Answers

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");
like image 81
Oleksandr Vorobiov Avatar answered Nov 14 '22 02:11

Oleksandr Vorobiov


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.

like image 22
Thomas Simeroth Avatar answered Nov 14 '22 02:11

Thomas Simeroth


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();
});
like image 28
Grant Miller Avatar answered Nov 14 '22 02:11

Grant Miller