diff --git a/packages/playwright-core/src/server/injected/injectedScript.ts b/packages/playwright-core/src/server/injected/injectedScript.ts index 371aa6ec51..ad016c5491 100644 --- a/packages/playwright-core/src/server/injected/injectedScript.ts +++ b/packages/playwright-core/src/server/injected/injectedScript.ts @@ -870,9 +870,19 @@ export class InjectedScript { let container: Document | ShadowRoot | null = document; let element: Element | undefined; while (container) { - // elementFromPoint works incorrectly in Chromium (http://crbug.com/1188919), - // so we use elementsFromPoint instead. + // All browsers have different behavior around elementFromPoint and elementsFromPoint. + // https://github.com/w3c/csswg-drafts/issues/556 + // http://crbug.com/1188919 const elements: Element[] = container.elementsFromPoint(x, y); + const singleElement = container.elementFromPoint(x, y); + if (singleElement && elements[0] && parentElementOrShadowHost(singleElement) === elements[0]) { + const style = document.defaultView?.getComputedStyle(singleElement); + if (style?.display === 'contents') { + // Workaround a case where elementsFromPoint misses the inner-most element with display:contents. + // https://bugs.chromium.org/p/chromium/issues/detail?id=1342092 + elements.unshift(singleElement); + } + } const innerElement = elements[0] as Element | undefined; if (!innerElement || element === innerElement) break; diff --git a/tests/page/elementhandle-scroll-into-view.spec.ts b/tests/page/elementhandle-scroll-into-view.spec.ts index 918afebbe0..70705b05da 100644 --- a/tests/page/elementhandle-scroll-into-view.spec.ts +++ b/tests/page/elementhandle-scroll-into-view.spec.ts @@ -60,10 +60,16 @@ it('should wait for display:none to become visible', async ({ page, server }) => await testWaiting(page, div => div.style.display = 'block'); }); -it.fixme('should scroll display:contents into view', async ({ page, server }) => { +it('should scroll display:contents into view', async ({ page, browserName, browserMajorVersion }) => { + it.skip(browserName === 'chromium' && browserMajorVersion < 105, 'Needs https://chromium-review.googlesource.com/c/chromium/src/+/3758670'); it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/15034' }); await page.setContent(` +
diff --git a/tests/page/page-click-scroll.spec.ts b/tests/page/page-click-scroll.spec.ts index c052b6c548..d0207a857a 100644 --- a/tests/page/page-click-scroll.spec.ts +++ b/tests/page/page-click-scroll.spec.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { test as it } from './pageTest'; +import { expect, test as it } from './pageTest'; it('should not hit scroll bar', async ({ page, browserName, platform }) => { it.fixme(browserName === 'webkit' && platform === 'darwin'); @@ -37,3 +37,43 @@ it('should not hit scroll bar', async ({ page, browserName, platform }) => { `); await page.click('text=Story', { timeout: 2000 }); }); + +it('should scroll into view display:contents', async ({ page, browserName, browserMajorVersion }) => { + it.skip(browserName === 'chromium' && browserMajorVersion < 105, 'Needs https://chromium-review.googlesource.com/c/chromium/src/+/3758670'); + + await page.setContent(` +
filler
+
+ Example text, and button here: + +
+ `); + await page.click('text=click me', { timeout: 5000 }); + expect(await page.evaluate('window._clicked')).toBe(true); +}); + +it('should scroll into view display:contents with a child', async ({ page, browserName, browserMajorVersion }) => { + it.skip(browserName === 'chromium' && browserMajorVersion < 105, 'Needs https://chromium-review.googlesource.com/c/chromium/src/+/3758670'); + + await page.setContent(` +
filler
+ Example text, and button here: + + `); + await page.click('text=click me', { timeout: 5000 }); + expect(await page.evaluate('window._clicked')).toBe(true); +}); + +it('should scroll into view display:contents with position', async ({ page, browserName }) => { + it.fixme(browserName === 'chromium', 'DOM.getBoxModel does not work for display:contents'); + + await page.setContent(` +
filler
+
+ Example text, and button here: + +
+ `); + await page.click('text=click me', { position: { x: 5, y: 5 }, timeout: 5000 }); + expect(await page.evaluate('window._clicked')).toBe(true); +});