Skip to content

[Bug]: expect(locator).toHaveScreenshot({ mask: [locators] }) is affected by page backdrop styles #41504

Description

@ifwemkrad

Version

1.60.0

Steps to reproduce

  1. Run following code with on version 1.58.2
  2. Update to 1.59.0 (up to 1.61.1) and run the tests again
import { expect, test } from "@playwright/test";

test("masked screenshot with global backdrop styling", async ({ page }) => {
  await page.setContent(`
    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>Playwright Mask Backdrop Repro</title>
        <style>
          html,
          body {
            margin: 0;
            padding: 0;
          }

          body {
            background: #ffffff;
            font-family: sans-serif;
          }

          main[role="main"] {
            width: 420px;
            height: 280px;
            background: rgb(243, 243, 243);
            border: 1px solid rgb(180, 180, 180);
            position: relative;
            box-sizing: border-box;
            overflow: hidden;
          }

          h1 {
            margin: 12px;
            font-size: 18px;
          }

          p {
            margin: 12px;
          }

          #probe {
            position: absolute;
            top: 70px;
            left: 12px;
            width: 180px;
            height: 42px;
            box-sizing: border-box;
            border: 3px solid rgb(0, 102, 204);
            background: rgb(255, 255, 255);
            color: rgb(0, 0, 0);
            font-size: 16px;
            padding: 6px 8px;
          }

          #secret {
            position: absolute;
            top: 140px;
            left: 155px;
            width: 80px;
            height: 80px;
            background: rgb(30, 30, 30);
          }

          /* Intentionally broad backdrop style to trigger interaction with popover-backed overlays. */
          ::backdrop,
          ::-webkit-backdrop {
            background: rgba(0, 0, 0, 0.35);
          }
        </style>
      </head>
      <body>
        <main role="main">
          <h1>Mask + Backdrop Repro</h1>
          <p>Blue bordered input should stay visually unchanged when applying mask.</p>
          <input id="probe" value="UNMASKED AREA" readonly />
          <div id="secret" aria-label="masked-target"></div>
        </main>
      </body>
    </html>
  `);

  const container = page.getByRole("main");
  const masked = page.locator("#secret");

  await expect(masked).toBeVisible();

  await expect(container).toHaveScreenshot("repro-no-mask.png");

  await expect(container).toHaveScreenshot("repro-with-mask.png", {
    mask: [masked],
  });
});

Expected behavior

  1. The tests do pass
  2. In visual comparison - the area around masked element is not grayed out

Actual behavior

  1. The tests fail
  2. The whole viewport has the gray overlay

Sample from test report:

Image

Additional context

Initially, an update to 1.60.0 from 1.58.2 was made, but then the actual breaking change was observed when updating from 1.58.2 to 1.59.0.

As a workaround, the following code fixed the issue:

  await page.evaluate(() => {
    const cspMeta = document
      .querySelector("meta[http-equiv='Content-Security-Policy']")
      ?.getAttribute("content");
    const cspNonce = cspMeta?.match(/'nonce-([^']+)'/)?.[1];
    const styleNonce =
      cspNonce ??
      document.querySelector("script[nonce], style[nonce]")?.getAttribute("nonce");

    const style = document.createElement("style");
    if (styleNonce) style.setAttribute("nonce", styleNonce);
    style.textContent = `
      x-pw-glass::backdrop,
      x-pw-glass::-webkit-backdrop {
        background: transparent !important;
        opacity: 0 !important;
      }
    `;
    document.head.appendChild(style);
  });

Environment

System:
    OS: Windows 11 10.0.26100
    CPU: (22) x64 Intel(R) Core(TM) Ultra 7 165H
    Memory: 32.44 GB / 63.45 GB
  Binaries:
    Node: 24.13.0 - C:\Program Files\nodejs\node.EXE
    npm: 11.9.0 - C:\Program Files\nodejs\npm.CMD
  IDEs:
    VSCode: 1.126.0 - C:\Users\REDACTED\AppData\Local\Programs\Microsoft VS Code\bin\code.CMD
  Languages:
    Bash: 5.2.21 - C:\WINDOWS\system32\bash.EXE
  npmPackages:
    @playwright/test: ^1.59.1 => 1.59.1

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions