From b5beeab98b937d49a8d8b9514e5bd6b999fdb421 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Wed, 18 May 2022 10:01:34 -0700 Subject: [PATCH] fix(click): climb the hit target hierarchy to anchor (#14235) fix(click): climb the hit target hierarcchy to anchor --- .../src/server/injected/injectedScript.ts | 9 ++++----- tests/page/page-click.spec.ts | 12 ++++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/playwright-core/src/server/injected/injectedScript.ts b/packages/playwright-core/src/server/injected/injectedScript.ts index 6aa6ac1e52..0ce2f37950 100644 --- a/packages/playwright-core/src/server/injected/injectedScript.ts +++ b/packages/playwright-core/src/server/injected/injectedScript.ts @@ -716,15 +716,15 @@ export class InjectedScript { } checkHitTargetAt(node: Node, point: { x: number, y: number }): 'error:notconnected' | 'done' | { hitTargetDescription: string } { - let element: Element | null | undefined = node.nodeType === Node.ELEMENT_NODE ? (node as Element) : node.parentElement; + const element: Element | null | undefined = node.nodeType === Node.ELEMENT_NODE ? (node as Element) : node.parentElement; if (!element || !element.isConnected) return 'error:notconnected'; - element = element.closest('button, [role=button]') || element; const hitElement = this.deepElementFromPoint(document, point.x, point.y); return this._expectHitTargetParent(hitElement, element); } private _expectHitTargetParent(hitElement: Element | undefined, targetElement: Element) { + targetElement = targetElement.closest('button, [role=button], a, [role=link]') || targetElement; const hitParents: Element[] = []; while (hitElement && hitElement !== targetElement) { hitParents.push(hitElement); @@ -753,10 +753,9 @@ export class InjectedScript { } setupHitTargetInterceptor(node: Node, action: 'hover' | 'tap' | 'mouse', blockAllEvents: boolean): HitTargetInterceptionResult | 'error:notconnected' { - const maybeElement: Element | null | undefined = node.nodeType === Node.ELEMENT_NODE ? (node as Element) : node.parentElement; - if (!maybeElement || !maybeElement.isConnected) + const element: Element | null | undefined = node.nodeType === Node.ELEMENT_NODE ? (node as Element) : node.parentElement; + if (!element || !element.isConnected) return 'error:notconnected'; - const element = maybeElement.closest('button, [role=button]') || maybeElement; const events = { 'hover': kHoverHitTargetInterceptorEvents, diff --git a/tests/page/page-click.spec.ts b/tests/page/page-click.spec.ts index bc865bcedf..572f4dd126 100644 --- a/tests/page/page-click.spec.ts +++ b/tests/page/page-click.spec.ts @@ -611,6 +611,18 @@ it('should climb up to [role=button]', async ({ page }) => { expect(await page.evaluate('__CLICKED')).toBe(true); }); +it('should climb up to a anchor', async ({ page }) => { + await page.setContent(`
Inner
`); + await page.click('#inner'); + expect(await page.evaluate('__CLICKED')).toBe(true); +}); + +it('should climb up to a [role=link]', async ({ page }) => { + await page.setContent(`
Inner
`); + await page.click('#inner'); + expect(await page.evaluate('__CLICKED')).toBe(true); +}); + it('should wait for BUTTON to be clickable when it has pointer-events:none', async ({ page }) => { await page.setContent(''); let done = false;