mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-28 08:22:24 +00:00
Injects CSS to hide scrollbars in visual regression tests (`tests/visual/kitchen-sink.spec.ts`) to ensure a consistent viewport width of 1280px across different environments. This prevents failures caused by scrollbar width expanding the screenshot or shifting layout content. Also updates the `video-modal-mobile` test block to use the correct baseline key constant instead of an undefined variable. Baselines have been regenerated with the scrollbars hidden.
213 lines
6.3 KiB
TypeScript
213 lines
6.3 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import pixelmatch from "pixelmatch";
|
|
import { PNG } from "pngjs";
|
|
import {
|
|
getBaseline,
|
|
saveBaselines,
|
|
setBaseline,
|
|
type BaselineKey,
|
|
type KitchenSinkTheme
|
|
} from "./baseline-store";
|
|
|
|
const THEMES: { name: KitchenSinkTheme; value?: string }[] = [
|
|
{ name: "default" },
|
|
{ name: "light", value: "light" },
|
|
{ name: "contrast", value: "contrast" }
|
|
];
|
|
|
|
const VIDEO_MODAL_BASELINE_KEY = "video-modal-mobile" as BaselineKey;
|
|
|
|
const MAX_DIFF_RATIO = 0.001;
|
|
const UPDATE_BASELINES = process.env.UPDATE_VISUAL_BASELINES === "1";
|
|
|
|
test.describe.configure({ mode: "serial" });
|
|
|
|
test.use({
|
|
viewport: { width: 1280, height: 720 }
|
|
});
|
|
|
|
test.afterAll(async () => {
|
|
if (UPDATE_BASELINES) {
|
|
saveBaselines();
|
|
}
|
|
});
|
|
|
|
test.describe("design system kitchen sink", () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.emulateMedia({ reducedMotion: "reduce" });
|
|
});
|
|
|
|
for (const theme of THEMES) {
|
|
test(`renders ${theme.name} theme without regressions`, async ({
|
|
page
|
|
}, testInfo) => {
|
|
await page.goto("/docs/kitchen-sink.html", { waitUntil: "networkidle" });
|
|
|
|
await page.addStyleTag({
|
|
content:
|
|
"*, *::before, *::after { transition-duration: 0s !important; animation-duration: 0s !important; animation-delay: 0s !important; caret-color: transparent !important; } ::-webkit-scrollbar { display: none; } body { -ms-overflow-style: none; scrollbar-width: none; }"
|
|
});
|
|
|
|
await page.evaluate((value) => {
|
|
const root = document.documentElement;
|
|
const storageKey = "bitvid-docs-theme";
|
|
|
|
if (!value) {
|
|
root.removeAttribute("data-theme");
|
|
window.localStorage.removeItem(storageKey);
|
|
} else {
|
|
root.setAttribute("data-theme", value);
|
|
window.localStorage.setItem(storageKey, value);
|
|
}
|
|
}, theme.value ?? null);
|
|
|
|
await page.waitForTimeout(100);
|
|
|
|
const screenshotBuffer = await page.screenshot({
|
|
type: "png",
|
|
fullPage: true,
|
|
animations: "disabled"
|
|
});
|
|
|
|
if (UPDATE_BASELINES) {
|
|
setBaseline(theme.name, screenshotBuffer);
|
|
await testInfo.attach(`${theme.name}-actual.png`, {
|
|
body: screenshotBuffer,
|
|
contentType: "image/png"
|
|
});
|
|
return;
|
|
}
|
|
|
|
const baselineBuffer = getBaseline(theme.name);
|
|
const actual = PNG.sync.read(screenshotBuffer);
|
|
const expected = PNG.sync.read(baselineBuffer);
|
|
|
|
expect(actual.width).toBe(expected.width);
|
|
expect(actual.height).toBe(expected.height);
|
|
|
|
const diff = new PNG({ width: actual.width, height: actual.height });
|
|
const diffPixelCount = pixelmatch(
|
|
actual.data,
|
|
expected.data,
|
|
diff.data,
|
|
actual.width,
|
|
actual.height,
|
|
{ threshold: 0.1 }
|
|
);
|
|
|
|
const diffRatio = diffPixelCount / (actual.width * actual.height);
|
|
|
|
if (diffPixelCount > 0) {
|
|
await testInfo.attach(`${theme.name}-actual.png`, {
|
|
body: screenshotBuffer,
|
|
contentType: "image/png"
|
|
});
|
|
await testInfo.attach(`${theme.name}-baseline.png`, {
|
|
body: baselineBuffer,
|
|
contentType: "image/png"
|
|
});
|
|
await testInfo.attach(`${theme.name}-diff.png`, {
|
|
body: PNG.sync.write(diff),
|
|
contentType: "image/png"
|
|
});
|
|
}
|
|
|
|
expect(diffRatio).toBeLessThanOrEqual(MAX_DIFF_RATIO);
|
|
});
|
|
}
|
|
});
|
|
|
|
test.describe("video modal mobile regression", () => {
|
|
test.use({ viewport: { width: 390, height: 844 } });
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.emulateMedia({ reducedMotion: "reduce" });
|
|
});
|
|
|
|
test("renders video modal without regressions", async ({ page }, testInfo) => {
|
|
await page.goto("/components/video-modal.html", {
|
|
waitUntil: "networkidle"
|
|
});
|
|
|
|
await page.addStyleTag({
|
|
content:
|
|
"*, *::before, *::after { transition-duration: 0s !important; animation-duration: 0s !important; animation-delay: 0s !important; caret-color: transparent !important; } ::-webkit-scrollbar { display: none; } body { -ms-overflow-style: none; scrollbar-width: none; }"
|
|
});
|
|
|
|
await page.evaluate(() => {
|
|
const modal = document.getElementById("playerModal");
|
|
if (!modal) {
|
|
throw new Error("Missing player modal root element");
|
|
}
|
|
|
|
modal.classList.remove("hidden");
|
|
modal.removeAttribute("hidden");
|
|
|
|
modal.setAttribute("data-ds", "new");
|
|
|
|
const html = document.documentElement;
|
|
if (html) {
|
|
html.setAttribute("data-ds", "new");
|
|
}
|
|
if (document.body) {
|
|
document.body.setAttribute("data-ds", "new");
|
|
}
|
|
|
|
window.scrollTo(0, 0);
|
|
});
|
|
|
|
await page.waitForTimeout(100);
|
|
|
|
const screenshotBuffer = await page.screenshot({
|
|
type: "png",
|
|
fullPage: true,
|
|
animations: "disabled"
|
|
});
|
|
|
|
if (UPDATE_BASELINES) {
|
|
setBaseline(VIDEO_MODAL_BASELINE_KEY, screenshotBuffer);
|
|
await testInfo.attach(`${VIDEO_MODAL_BASELINE_KEY}-actual.png`, {
|
|
body: screenshotBuffer,
|
|
contentType: "image/png"
|
|
});
|
|
return;
|
|
}
|
|
|
|
const baselineBuffer = getBaseline(VIDEO_MODAL_BASELINE_KEY);
|
|
const actual = PNG.sync.read(screenshotBuffer);
|
|
const expected = PNG.sync.read(baselineBuffer);
|
|
|
|
expect(actual.width).toBe(expected.width);
|
|
expect(actual.height).toBe(expected.height);
|
|
|
|
const diff = new PNG({ width: actual.width, height: actual.height });
|
|
const diffPixelCount = pixelmatch(
|
|
actual.data,
|
|
expected.data,
|
|
diff.data,
|
|
actual.width,
|
|
actual.height,
|
|
{ threshold: 0.1 }
|
|
);
|
|
|
|
const diffRatio = diffPixelCount / (actual.width * actual.height);
|
|
|
|
if (diffPixelCount > 0) {
|
|
await testInfo.attach(`${VIDEO_MODAL_BASELINE_KEY}-actual.png`, {
|
|
body: screenshotBuffer,
|
|
contentType: "image/png"
|
|
});
|
|
await testInfo.attach(`${VIDEO_MODAL_BASELINE_KEY}-baseline.png`, {
|
|
body: baselineBuffer,
|
|
contentType: "image/png"
|
|
});
|
|
await testInfo.attach(`${VIDEO_MODAL_BASELINE_KEY}-diff.png`, {
|
|
body: PNG.sync.write(diff),
|
|
contentType: "image/png"
|
|
});
|
|
}
|
|
|
|
expect(diffRatio).toBeLessThanOrEqual(MAX_DIFF_RATIO);
|
|
});
|
|
});
|