e2e/font-size.spec.ts
Linked repository file from this build.
import { expect, test, type Page } from "@playwright/test";
async function setFontSize(page: Page, px: number) {
await page.addInitScript((size) => {
const key = "qccrm.appearance";
let stored: Record<string, unknown> = {};
try {
stored = JSON.parse(localStorage.getItem(key) || "null") || {};
} catch {
stored = {};
}
localStorage.setItem(key, JSON.stringify({ ...stored, fontSize: size }));
}, px);
}
async function pageOverflows(page: Page) {
return page.evaluate(
() => document.documentElement.scrollWidth > document.documentElement.clientWidth + 1,
);
}
async function openAppearance(page: Page) {
await page
.context()
.addCookies([{ name: "qc-test-staff", value: "401", domain: "localhost", path: "/" }]);
await page.goto("/imports");
await page.getByRole("button", { name: "Appearance", exact: true }).click();
}
test("font size slider persists a pixel value across reload", async ({ page }) => {
await page.setViewportSize({ width: 1440, height: 1000 });
await openAppearance(page);
const slider = page.locator(".appearance-settings").getByRole("slider", { name: "Font size" });
await slider.fill("22");
await slider.blur();
await expect(page.locator("html")).toHaveCSS("font-size", "22px");
await page.keyboard.press("Escape");
await page.reload();
await expect(page.locator("html")).toHaveCSS("font-size", "22px");
});
test("font size applies only after slider release", async ({ page }) => {
await setFontSize(page, 16);
await page.setViewportSize({ width: 1440, height: 1000 });
await openAppearance(page);
const slider = page.locator(".appearance-settings").getByRole("slider", { name: "Font size" });
const settings = page.locator(".appearance-settings");
const bounds = await slider.boundingBox();
if (!bounds) throw new Error("Font size slider is not visible");
const y = bounds.y + bounds.height / 2;
await page.mouse.move(bounds.x + bounds.width * 0.2, y);
await page.mouse.down();
await page.mouse.move(bounds.x + bounds.width * 0.6, y, { steps: 8 });
await expect(slider).toHaveValue("24");
await expect(settings.locator("output")).toHaveText("24");
await expect(page.locator("html")).toHaveCSS("font-size", "16px");
expect(
await page.evaluate(() => JSON.parse(localStorage.getItem("qccrm.appearance")!).fontSize),
).toBe(16);
// Release outside the slider to check pointer capture.
await page.mouse.move(bounds.x + bounds.width * 0.6, y + 40);
await page.mouse.up();
await expect(page.locator("html")).toHaveCSS("font-size", "24px");
expect(
await page.evaluate(() => JSON.parse(localStorage.getItem("qccrm.appearance")!).fontSize),
).toBe(24);
await slider.focus();
await page.keyboard.down("ArrowRight");
await expect(slider).toHaveValue("26");
await expect(page.locator("html")).toHaveCSS("font-size", "24px");
await page.keyboard.up("ArrowRight");
await expect(page.locator("html")).toHaveCSS("font-size", "26px");
});
test("home and search chrome stay on screen at 32px", async ({ page }) => {
await setFontSize(page, 32);
await page.setViewportSize({ width: 1440, height: 1000 });
await page.goto("/dashboard");
await expect(page.locator("html")).toHaveCSS("font-size", "32px");
await expect(page.getByRole("link", { name: "Home", exact: true })).toBeVisible();
await expect(page.getByRole("textbox", { name: "Search reviews" })).toBeVisible();
await expect(page.getByRole("heading", { name: "Home", exact: true })).toBeVisible();
expect(await pageOverflows(page), "Home should not need a horizontal page scroll").toBe(false);
await page.getByRole("button", { name: "Appearance", exact: true }).click();
const slider = page.locator(".appearance-settings").getByRole("slider", { name: "Font size" });
await expect(slider).toBeVisible();
await expect(slider).toBeInViewport();
await page.keyboard.press("Escape");
await page.goto("/search");
await expect(page.getByRole("button", { name: "Add filter", exact: true })).toBeVisible();
await expect(page.getByRole("button", { name: "Search reviews", exact: true })).toBeVisible();
await expect(page.getByRole("button", { name: "Search reviews", exact: true })).toBeInViewport();
expect(await pageOverflows(page), "Search chrome should not force a horizontal page scroll").toBe(
false,
);
await page.goto("/reviews/e1c8806f-915a-573b-a859-857bbd99e075");
await expect(page.locator("html")).toHaveCSS("font-size", "32px");
for (const name of ["Household", "Computation", "Review", "Documents", "Activity"]) {
const tab = page.getByRole("tab", { name, exact: true });
await expect(tab).toBeVisible();
await expect(tab, `${name} tab label should stay readable`).toBeInViewport();
expect(
await tab.evaluate((el) => el.scrollWidth <= el.clientWidth + 1),
`${name} tab should not clip its label`,
).toBe(true);
}
expect(await pageOverflows(page), "Review chrome should not force a horizontal page scroll").toBe(
false,
);
});