import { expect } from "@std/expect";
import { afterAll, beforeAll, describe, it as test } from "@std/testing/bdd";
import type { Browser } from "playwright";
import { capturePreparedLayers } from "#scripts/screenshots/capture.ts";
import type { ScreenshotLayerName } from "#scripts/screenshots/layers.ts";
import {
countLayerRgbPixels,
countRgbPixels,
expectLayersRecombine,
expectOnlyLayerColor,
launchScreenshotBrowser,
layerStyle,
withLayer,
withPage,
} from "./screenshots-browser-helpers.ts";
describe("screenshot layer boundary browser contracts", () => {
let browser: Browser;
beforeAll(async () => {
browser = await launchScreenshotBrowser();
});
afterAll(async () => {
await browser.close();
});
test("applies layer masks inside open shadow roots", async () => {
await withPage(browser, '
', async (page) => {
await page.locator("#host").evaluate((host) => {
const root = host.attachShadow({ mode: "open" });
root.innerHTML = ``;
});
const shadowStyle = (layer: ScreenshotLayerName, property: string) =>
withLayer(page, layer, () =>
page.locator("#host").evaluate((host, propertyName) => {
const button = host.shadowRoot?.querySelector("button");
if (!button) throw new Error("Missing shadow button.");
return getComputedStyle(button).getPropertyValue(propertyName);
}, property),
);
expect(await shadowStyle("background", "visibility")).toBe("hidden");
expect(await shadowStyle("controls", "-webkit-text-fill-color")).toBe(
"rgba(0, 0, 0, 0)",
);
expect(await shadowStyle("text", "background-color")).toBe(
"rgba(0, 0, 0, 0)",
);
});
});
test("keeps disclosure markers out of the text layer", async () => {
await withPage(
browser,
"More
",
async (page) => {
const redPixels = countLayerRgbPixels(page, "summary", [255, 0, 0]);
expect(await redPixels("controls")).toBeGreaterThan(0);
expect(await redPixels("text")).toBe(0);
},
);
});
test("keeps SVG control labels only in the text layer", async () => {
await withPage(
browser,
'',
async (page) => {
const { layers } = await capturePreparedLayers(page);
await expectOnlyLayerColor(layers, [0, 0, 255], "text");
},
);
});
test("keeps styled direct body text unchanged in one layer", async () => {
await withPage(
browser,
`
Words`,
async (page) => {
const { layers } = await capturePreparedLayers(page);
await expectOnlyLayerColor(layers, [0, 0, 255], "background");
for (const layer of Object.values(layers)) {
expect(await countRgbPixels(layer, [255, 0, 0])).toBe(0);
}
},
);
});
test("keeps whole-paint control descendants with their control", async () => {
await withPage(
browser,
``,
async (page) => {
const { layers } = await capturePreparedLayers(page);
await expectOnlyLayerColor(layers, [255, 0, 0], "background");
},
);
});
test("separates body-generated content", async () => {
await withPage(
browser,
``,
async (page) => {
expect(
await layerStyle(
page,
"background",
"body",
"-webkit-text-fill-color",
"::before",
),
).toBe("rgba(0, 0, 0, 0)");
expect(
await layerStyle(page, "controls", "body", "visibility", "::before"),
).toBe("hidden");
expect(
await layerStyle(
page,
"text",
"body",
"background-color",
"::before",
),
).toBe("rgba(0, 0, 0, 0)");
},
);
});
test("puts for-linked gallery labels in the controls layer", async () => {
await withPage(
browser,
'',
async (page) => {
expect(
await layerStyle(page, "background", "label", "visibility"),
).toBe("hidden");
expect(await layerStyle(page, "controls", "label", "visibility")).toBe(
"visible",
);
},
);
});
test("does not reveal controls hidden by themselves or an ancestor", async () => {
await withPage(
browser,
`
`,
async (page) => {
const hiddenVisibility = (selector: string) =>
withLayer(page, "controls", () =>
page
.locator(selector)
.evaluate((element) => getComputedStyle(element).visibility),
);
expect(await hiddenVisibility("body > button")).toBe("hidden");
expect(await hiddenVisibility("div button")).toBe("hidden");
await expectLayersRecombine(page, "hidden controls");
},
);
});
test("keeps border images out of the text layer", async () => {
await withPage(
browser,
`Words
`,
async (page) => {
const { layers } = await capturePreparedLayers(page);
await expectOnlyLayerColor(layers, [255, 0, 0], "background");
},
);
});
});