From 85b01056b61bb7a445b4896750bdb0943509f622 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Fri, 18 Mar 2022 18:20:48 -0700 Subject: [PATCH] fix(click): workaround elementsFromPoint issue in Chromium (#12888) Block elements inside elements are not returned correctly from `document.elementsFromPoint(x, y)` in some cases. See https://bugs.chromium.org/p/chromium/issues/detail?id=1307458 for details. --- .../src/server/injected/injectedScript.ts | 7 ++- tests/hit-target.spec.ts | 59 +++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/packages/playwright-core/src/server/injected/injectedScript.ts b/packages/playwright-core/src/server/injected/injectedScript.ts index f88ca5b8d2..b83232e00b 100644 --- a/packages/playwright-core/src/server/injected/injectedScript.ts +++ b/packages/playwright-core/src/server/injected/injectedScript.ts @@ -804,8 +804,11 @@ export class InjectedScript { while (container) { // elementFromPoint works incorrectly in Chromium (http://crbug.com/1188919), // so we use elementsFromPoint instead. - const elements = (container as Document).elementsFromPoint(x, y); - const innerElement = elements[0] as Element | undefined; + const elements: Element[] = container.elementsFromPoint(x, y); + let innerElement = elements[0] as Element | undefined; + // Workaround https://bugs.chromium.org/p/chromium/issues/detail?id=1307458. + if (elements[0] && elements[1] && elements[0].contains(elements[1]) && container.elementFromPoint(x, y) === elements[1]) + innerElement = elements[1]; if (!innerElement || element === innerElement) break; element = innerElement; diff --git a/tests/hit-target.spec.ts b/tests/hit-target.spec.ts index dc499bd593..57c3aaf802 100644 --- a/tests/hit-target.spec.ts +++ b/tests/hit-target.spec.ts @@ -180,3 +180,62 @@ it('should work with drag and drop that moves the element under cursor', async ( await page.dragAndDrop('#from', '#to'); await expect(page.locator('#to')).toHaveText('Dropped'); }); + +it('should work with block inside inline', async ({ page, server }) => { + await page.goto(server.EMPTY_PAGE); + await page.setContent(` +
+ +
+ Romimine +
+
+
+ `); + await page.locator('#target').click(); + expect(await page.evaluate('window._clicked')).toBe(true); +}); + +it('should work with block-block-block inside inline-inline', async ({ page, server }) => { + await page.goto(server.EMPTY_PAGE); + await page.setContent(` +
+ +
+ + +
+

+ Romimine +

+
+
+ +
+ +
+ `); + await page.locator('#target').click(); + await expect(page).toHaveURL(server.EMPTY_PAGE + '#yay'); +}); + +it('should work with block inside inline in shadow dom', async ({ page, server }) => { + await page.goto(server.EMPTY_PAGE); + await page.setContent(` +
+
+ + `); + await page.locator('#target').click(); + expect(await page.evaluate('window._clicked')).toBe(true); +});