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.
This commit is contained in:
Dmitry Gozman 2022-03-18 18:20:48 -07:00 committed by GitHub
parent 98ed81dc00
commit 85b01056b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 64 additions and 2 deletions

View File

@ -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;

View File

@ -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(`
<div>
<span>
<div id="target" onclick="window._clicked=true">
Romimine
</div>
</span>
</div>
`);
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(`
<div>
<a href="#ney">
<div>
<span>
<a href="#yay">
<div>
<h3 id="target">
Romimine
</h3>
</div>
</a>
</span>
</div>
</a>
</div>
`);
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(`
<div>
</div>
<script>
const root = document.querySelector('div');
const shadowRoot = root.attachShadow({ mode: 'open' });
const span = document.createElement('span');
shadowRoot.appendChild(span);
const div = document.createElement('div');
span.appendChild(div);
div.id = 'target';
div.addEventListener('click', () => window._clicked = true);
div.textContent = 'Hello';
</script>
`);
await page.locator('#target').click();
expect(await page.evaluate('window._clicked')).toBe(true);
});