diff --git a/package.json b/package.json index 4ab705a26..bff383280 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "test-e2e-testplane": "npm run test-e2e-testplane:generate-fixtures && npm run test-e2e-testplane:run-tests", "test-e2e-testplane:run-tests": "node bin/testplane --config test/e2e/testplane.config.ts", "test-e2e-testplane:generate-fixtures": "node bin/testplane --config test/e2e/fixtures/basic-report/testplane.config.ts || true", - "test-e2e:gui": "node bin/testplane --config test/e2e/testplane.config.ts gui", + "test-e2e-testplane:gui": "node bin/testplane --config test/e2e/testplane.config.ts gui", "test-browser-env": "TS_NODE_PROJECT=./test/browser-env/tsconfig.json node bin/testplane -r tsconfig-paths/register --config test/browser-env/testplane.config.ts", "test-browser-env:gui": "TS_NODE_PROJECT=./test/browser-env/tsconfig.json node bin/testplane gui -r tsconfig-paths/register --config test/browser-env/testplane.config.ts", "toc": "doctoc docs --title '### Contents'", diff --git a/src/browser/client-scripts/screen-shooter/operations.ts b/src/browser/client-scripts/screen-shooter/operations.ts index 4f1486969..ba6a5dbb2 100644 --- a/src/browser/client-scripts/screen-shooter/operations.ts +++ b/src/browser/client-scripts/screen-shooter/operations.ts @@ -48,6 +48,16 @@ export function computeScrollOffset(element: Element): Coord<"page", "css", "y"> } export function computeViewportSize(): Size<"css"> { + const visualViewport = window.visualViewport; + + // Visual viewport occasionally returns more correct values than innerWidth/Height, but may not be available in older browsers + if (visualViewport && visualViewport.width > 0 && visualViewport.height > 0) { + return { + width: visualViewport.width as Length<"css", "x">, + height: visualViewport.height as Length<"css", "y"> + }; + } + return { width: window.innerWidth as Length<"css", "x">, height: window.innerHeight as Length<"css", "y"> @@ -333,7 +343,8 @@ export function computeSafeArea( const scrollParentBcr = scrollParent.getBoundingClientRect(); topValue += isRootLikeElement(scrollParent) ? 0 : scrollParentBcr.top; shouldSkipZIndexCheck = - scrollParent === scrollEl || (isRootLikeElement(scrollParent) && isRootLikeElement(scrollEl)); + captureElements.some(capEl => capEl === el || capEl.contains(el)) && + (scrollParent === scrollEl || (isRootLikeElement(scrollParent) && isRootLikeElement(scrollEl))); if (!isNaN(topValue)) { adjustedRect = { diff --git a/src/browser/screen-shooter/elements-screen-shooter.ts b/src/browser/screen-shooter/elements-screen-shooter.ts index 2d327d75d..52818be8f 100644 --- a/src/browser/screen-shooter/elements-screen-shooter.ts +++ b/src/browser/screen-shooter/elements-screen-shooter.ts @@ -631,6 +631,16 @@ export class ElementsScreenShooter { opts, async currentState => { if (currentState.captureSpecs.length === 0) { + if (iterations > 0) { + debug( + "Capture area disappeared after %d chunk(s), rendering already captured data for selectors: %s", + iterations, + selectorsToCapture.join("; "), + ); + + return; + } + throw new Error(getEmptyCaptureSpecsErrorMessage(selectorsToCapture)); } diff --git a/test/browser-env/screens/40bec12/chrome/compute-safe-area-root-sticky-behind-absolute-popup.png b/test/browser-env/screens/40bec12/chrome/compute-safe-area-root-sticky-behind-absolute-popup.png new file mode 100644 index 000000000..e43299c71 Binary files /dev/null and b/test/browser-env/screens/40bec12/chrome/compute-safe-area-root-sticky-behind-absolute-popup.png differ diff --git a/test/browser-env/tests/desktop/screenshooter/computeSafeArea.testplane.ts b/test/browser-env/tests/desktop/screenshooter/computeSafeArea.testplane.ts index 19432971b..bc875d537 100644 --- a/test/browser-env/tests/desktop/screenshooter/computeSafeArea.testplane.ts +++ b/test/browser-env/tests/desktop/screenshooter/computeSafeArea.testplane.ts @@ -336,6 +336,19 @@ describe("computeSafeArea", () => { await browser.assertView("compute-safe-area-stacking-context-filter-in-front"); }); + it("should not shrink when root sticky element is behind absolute popup target", async ({ browser }) => { + const { default: html } = await import("./fixtures/safe-areas/root-sticky-behind-absolute-popup.html?raw"); + document.body.innerHTML = html; + + const selectors = [".popup"]; + const safeArea = computeSafeArea(selectors); + const captureSpecs = computeCaptureSpecs(selectors); + + visualizeCaptureSpecs(captureSpecs); + visualizeSafeArea(safeArea.top, safeArea.height); + await browser.assertView("compute-safe-area-root-sticky-behind-absolute-popup"); + }); + it("should shrink for fixed header that creates stacking context via filter and is in front", async ({ browser, }) => { diff --git a/test/browser-env/tests/desktop/screenshooter/fixtures/safe-areas/root-sticky-behind-absolute-popup.html b/test/browser-env/tests/desktop/screenshooter/fixtures/safe-areas/root-sticky-behind-absolute-popup.html new file mode 100644 index 000000000..29d9885b2 --- /dev/null +++ b/test/browser-env/tests/desktop/screenshooter/fixtures/safe-areas/root-sticky-behind-absolute-popup.html @@ -0,0 +1,71 @@ + + +
+
Sticky filter behind popup
+ +
+

Listing card

+

The sticky filter belongs to page content and is below the popup in stacking order.

+
+
+ + diff --git a/test/e2e/screens/8b8b177/chrome/scroll-sensitive-popup.png b/test/e2e/screens/8b8b177/chrome/scroll-sensitive-popup.png new file mode 100644 index 000000000..f694d2589 Binary files /dev/null and b/test/e2e/screens/8b8b177/chrome/scroll-sensitive-popup.png differ diff --git a/test/e2e/static/capture-area-disappears-after-scroll.html b/test/e2e/static/capture-area-disappears-after-scroll.html new file mode 100644 index 000000000..297fbb4f2 --- /dev/null +++ b/test/e2e/static/capture-area-disappears-after-scroll.html @@ -0,0 +1,86 @@ + + + + + + Capture Area Disappears After Scroll + + + +
Safe area interference
+ +
+
Popup top
+
Popup middle
+
Popup bottom
+
+ + + + diff --git a/test/e2e/tests/assert-view.testplane.js b/test/e2e/tests/assert-view.testplane.js index 68ccd469b..e2cef5b92 100644 --- a/test/e2e/tests/assert-view.testplane.js +++ b/test/e2e/tests/assert-view.testplane.js @@ -61,6 +61,14 @@ describe("assertView", () => { }); }); + it("should use captured chunk when capture area disappears after scrolling", async ({ browser }) => { + await browser.url("capture-area-disappears-after-scroll.html"); + + await browser.assertView("scroll-sensitive-popup", "[data-testid=scroll-sensitive-popup]", { + captureElementFromTop: true, + }); + }); + it("should treat sticky content inside capture target as interference", async ({ browser }) => { await browser.url("sticky-interference-behind-capture-target.html");