From 7e09aa07de54c3ac9babc9084dfc2774ec58b831 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Fri, 22 Nov 2024 17:35:19 +0000 Subject: [PATCH] feat(trace): preserve the open state of popovers (#33728) --- .../trace/recorder/snapshotterInjected.ts | 7 +++++++ .../trace-viewer/src/sw/snapshotRenderer.ts | 7 +++++++ tests/library/trace-viewer.spec.ts | 17 +++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/packages/playwright-core/src/server/trace/recorder/snapshotterInjected.ts b/packages/playwright-core/src/server/trace/recorder/snapshotterInjected.ts index 0400c6deaf..4d575ef0e9 100644 --- a/packages/playwright-core/src/server/trace/recorder/snapshotterInjected.ts +++ b/packages/playwright-core/src/server/trace/recorder/snapshotterInjected.ts @@ -48,6 +48,7 @@ export function frameSnapshotStreamer(snapshotStreamer: string, removeNoScript: const kCustomElementsAttribute = '__playwright_custom_elements__'; const kCurrentSrcAttribute = '__playwright_current_src__'; const kBoundingRectAttribute = '__playwright_bounding_rect__'; + const kPopoverOpenAttribute = '__playwright_popover_open_'; // Symbols for our own info on Nodes/StyleSheets. const kSnapshotFrameId = Symbol('__playwright_snapshot_frameid_'); @@ -449,6 +450,12 @@ export function frameSnapshotStreamer(snapshotStreamer: string, removeNoScript: expectValue(value); attrs[kBoundingRectAttribute] = value; } + if ((element as HTMLElement).popover && (element as HTMLElement).matches && (element as HTMLElement).matches(':popover-open')) { + const value = 'true'; + expectValue(kPopoverOpenAttribute); + expectValue(value); + attrs[kPopoverOpenAttribute] = value; + } if (element.scrollTop) { expectValue(kScrollTopAttribute); expectValue(element.scrollTop); diff --git a/packages/trace-viewer/src/sw/snapshotRenderer.ts b/packages/trace-viewer/src/sw/snapshotRenderer.ts index f4e9d908fb..93363878ab 100644 --- a/packages/trace-viewer/src/sw/snapshotRenderer.ts +++ b/packages/trace-viewer/src/sw/snapshotRenderer.ts @@ -270,6 +270,13 @@ function snapshotScript(...targetIds: (string | undefined)[]) { (element as HTMLOptionElement).selected = element.getAttribute('__playwright_selected_') === 'true'; element.removeAttribute('__playwright_selected_'); } + for (const element of root.querySelectorAll(`[__playwright_popover_open_]`)) { + try { + (element as HTMLElement).showPopover(); + } catch { + } + element.removeAttribute('__playwright_popover_open_'); + } for (const targetId of targetIds) { for (const target of root.querySelectorAll(`[__playwright_target__="${targetId}"]`)) { diff --git a/tests/library/trace-viewer.spec.ts b/tests/library/trace-viewer.spec.ts index 7e64c62156..2bd7b85888 100644 --- a/tests/library/trace-viewer.spec.ts +++ b/tests/library/trace-viewer.spec.ts @@ -1572,3 +1572,20 @@ test('should show only one pointer with multilevel iframes', async ({ page, runA await expect.soft(snapshotFrame.frameLocator('iframe').locator('x-pw-pointer')).not.toBeAttached(); await expect.soft(snapshotFrame.frameLocator('iframe').frameLocator('iframe').locator('x-pw-pointer')).toBeVisible(); }); + +test('should show a popover', async ({ runAndTrace, page, server }) => { + const traceViewer = await runAndTrace(async () => { + await page.setContent(` + +
+
I'm a popover
+
+ `); + await page.getByRole('button').click(); + await expect(page.locator('div')).toBeVisible(); + }); + + const snapshot = await traceViewer.snapshotFrame('expect.toBeVisible'); + const popover = snapshot.locator('#pop'); + await expect.poll(() => popover.evaluate(e => e.matches(':popover-open'))).toBe(true); +});