From 741c649d5651b8768eb6f26c2a38731b97c16af0 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Thu, 31 Aug 2023 12:46:49 -0700 Subject: [PATCH] fix(trace viewer): make sure target inside shadow dom is highlighted (#26823) References #24532. --- .../src/server/injected/injectedScript.ts | 2 +- .../src/server/trace/recorder/snapshotter.ts | 2 +- .../trace/recorder/snapshotterInjected.ts | 2 +- packages/trace-viewer/src/snapshotRenderer.ts | 18 ++++++++++++------ tests/library/trace-viewer.spec.ts | 14 ++++++++++++++ 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/packages/playwright-core/src/server/injected/injectedScript.ts b/packages/playwright-core/src/server/injected/injectedScript.ts index 6bd763d43e..6013f35567 100644 --- a/packages/playwright-core/src/server/injected/injectedScript.ts +++ b/packages/playwright-core/src/server/injected/injectedScript.ts @@ -1133,7 +1133,7 @@ export class InjectedScript { bubbles: true, cancelable: true, detail: callId, - composed: false, + composed: true, }); for (const element of markedElements) element.dispatchEvent(customEvent); diff --git a/packages/playwright-core/src/server/trace/recorder/snapshotter.ts b/packages/playwright-core/src/server/trace/recorder/snapshotter.ts index 2db04b1278..2340f55a26 100644 --- a/packages/playwright-core/src/server/trace/recorder/snapshotter.ts +++ b/packages/playwright-core/src/server/trace/recorder/snapshotter.ts @@ -114,7 +114,7 @@ export class Snapshotter { bubbles: true, cancelable: true, detail: callId, - composed: false, + composed: true, }); element.dispatchEvent(customEvent); }, callId); diff --git a/packages/playwright-core/src/server/trace/recorder/snapshotterInjected.ts b/packages/playwright-core/src/server/trace/recorder/snapshotterInjected.ts index ae8e3de5d5..ee503eb043 100644 --- a/packages/playwright-core/src/server/trace/recorder/snapshotterInjected.ts +++ b/packages/playwright-core/src/server/trace/recorder/snapshotterInjected.ts @@ -136,7 +136,7 @@ export function frameSnapshotStreamer(snapshotStreamer: string) { if (!event.detail) return; const callId = event.detail as string; - (event.target as any).__playwright_target__ = callId; + (event.composedPath()[0] as any).__playwright_target__ = callId; }); } diff --git a/packages/trace-viewer/src/snapshotRenderer.ts b/packages/trace-viewer/src/snapshotRenderer.ts index 0dc67da521..dcea1d9670 100644 --- a/packages/trace-viewer/src/snapshotRenderer.ts +++ b/packages/trace-viewer/src/snapshotRenderer.ts @@ -104,9 +104,7 @@ export class SnapshotRenderer { const prefix = snapshot.doctype ? `` : ''; html = prefix + [ '', - ``, - ``, - `` + `` ].join('') + html; return { html, pageId: snapshot.pageId, frameId: snapshot.frameId, index: this._index }; @@ -195,8 +193,8 @@ function snapshotNodes(snapshot: FrameSnapshot): NodeSnapshot[] { return (snapshot as any)._nodes; } -function snapshotScript() { - function applyPlaywrightAttributes(unwrapPopoutUrl: (url: string) => string) { +function snapshotScript(...targetIds: (string | undefined)[]) { + function applyPlaywrightAttributes(unwrapPopoutUrl: (url: string) => string, ...targetIds: (string | undefined)[]) { const scrollTops: Element[] = []; const scrollLefts: Element[] = []; @@ -220,6 +218,14 @@ function snapshotScript() { element.removeAttribute('__playwright_selected_'); } + for (const targetId of targetIds) { + for (const target of root.querySelectorAll(`[__playwright_target__="${targetId}"]`)) { + const style = (target as HTMLElement).style; + style.outline = '2px solid #006ab1'; + style.backgroundColor = '#6fa8dc7f'; + } + } + for (const iframe of root.querySelectorAll('iframe, frame')) { const src = iframe.getAttribute('__playwright_src__'); if (!src) { @@ -303,7 +309,7 @@ function snapshotScript() { window.addEventListener('DOMContentLoaded', onDOMContentLoaded); } - return `\n(${applyPlaywrightAttributes.toString()})(${unwrapPopoutUrl.toString()})`; + return `\n(${applyPlaywrightAttributes.toString()})(${unwrapPopoutUrl.toString()}${targetIds.map(id => `, "${id}"`).join('')})`; } diff --git a/tests/library/trace-viewer.spec.ts b/tests/library/trace-viewer.spec.ts index 4f37c2d930..3614505a74 100644 --- a/tests/library/trace-viewer.spec.ts +++ b/tests/library/trace-viewer.spec.ts @@ -630,6 +630,20 @@ test('should highlight target elements', async ({ page, runAndTrace, browserName await expect.poll(() => highlightedDivs(frameExpect2)).toEqual(['multi', 'multi']); }); +test('should highlight target element in shadow dom', async ({ page, server, runAndTrace }) => { + const traceViewer = await runAndTrace(async () => { + await page.goto(server.PREFIX + '/shadow.html'); + await page.locator('button').click(); + await expect(page.locator('h1')).toHaveText('Hellow Shadow DOM v1'); + }); + + const framePageClick = await traceViewer.snapshotFrame('locator.click'); + await expect(framePageClick.locator('button')).toHaveCSS('background-color', 'rgba(111, 168, 220, 0.498)'); + + const frameExpect = await traceViewer.snapshotFrame('expect.toHaveText'); + await expect(frameExpect.locator('h1')).toHaveCSS('background-color', 'rgba(111, 168, 220, 0.498)'); +}); + test('should show action source', async ({ showTraceViewer }) => { const traceViewer = await showTraceViewer([traceFile]); await traceViewer.selectAction('locator.click');