playwright: [BUG] Page.click() doesn't work when target is covered by animating element

Context:

  • Playwright Version: 0.13.0
  • Operating System: macOS

Describe the bug

Hi team. I’m having an issue with page.click() failing. This is happening in the context of React and Vue apps. I haven’t been able to create a reliable reproduction, but I have a couple of clues.

  1. In cases where the click fails, the visual state of the element changes and it appears to be in a hover state
  2. If I use page.$eval(selector, (element) => element.click()) in these cases, the click does work

Could you shed some light on what the differences are between page.click(selector) and page.$eval(selector, (element) => element.click())? This may help me create a reproduction case for this issue.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 15 (10 by maintainers)

Most upvoted comments

@dgozman @pavelfeldman I was able to create a repro for one of my cases! It turns out that the element I was trying to click was covered by an invisible element. That element begins to animate out of the way upon hover, but at the time of the click it’s still covering the center of the button I want to click.

So IMO the bug is that Playwright should tell me that this element isn’t interactable, but instead it tells me it successfully clicked the button.

const { chromium } = require('playwright-chromium');

(async () => {
  const browser = await chromium.launch({
    headless: false,
    args: ['--window-size=1280,720'],
  });
  const page = await browser.newPage();

  await page.goto('https://cdpn.io/celeryclub/debug/yLYJLXM/WPMLYZQWGdPr', { waitUntil: 'networkidle0' });
  await page.click('.button');
  await page.waitFor(1000);
  // We should be on bing.com right now but we're still on the original page because the click didn't work

  await browser.close();
})();

Here’s the codepen link in case the debug URL expires. https://codepen.io/celeryclub/pen/yLYJLXM?editors=0110

@celeryclub thanks for the report!

Could you shed some light on what the differences are between page.click(selector) and page.$eval(selector, (element) => element.click())? This may help me create a reproduction case for this issue.

page.$eval(selector, (element) => element.click()) performs a soft programmatic click on the element that corresponds to the selector.

  • Programmatic click will happen even if the element is invisible, has zero size, is behind another element or is otherwise not interactable.
  • Programmatic click is not trusted, see event.isTrusted, it’ll be false, the page would know it was injected.

page.click(selector) is a real click for testing. It’ll locate the element, wait for it to become visible, wait for it to receive input events when clicked in the center of its box, wait for it to stop moving. It’ll then perform mouse operations as if the user was clicking the mouse or tapping a phone screen. Browser would think those are real events, they also will be trusted.

Run your app with DEBUG=pw:input to see where it stalls. It is likely that the last line of the log will be waiting for element to receive pointer events at (x, y).