microsoft / microsoft/playwright
[Bug]: expect(locator).toHaveScreenshot({ mask: [locators] }) is affected by page backdrop styles
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 96.3k
- Forks
- 6.5k
- Avg merge
- 1d 6h
- Merged PRs (30d)
- 180
Description
### 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
```typescript
import { expect, test } from "@playwright/test";
test("masked screenshot with global backdrop styling", async ({ page }) => {
await page.setContent(`
Playwright Mask Backdrop Repro
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);
}
Mask + Backdrop Repro
Blue bordered input should stay visually unchanged when applying mask.
`);
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:
### 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:
```ts
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
```shell
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
```
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the supplied TypeScript reproduction with Playwright versions 1.58.2 through 1.61.1, focusing on expect(container).toHaveScreenshot() with mask: [masked]. Compare the masked and unmasked screenshots and inspect the x-pw-glass backdrop behavior; done means the masked area is handled without graying the rest of the viewport and the tests pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100