CI / check (push) Successful in 32s
CI / tests-imaging-browsers (push) Successful in 1m34s
CI / tests-integration (push) Successful in 1m59s
CI / tests-unit (push) Successful in 2m2s
CI / tests-quality (push) Successful in 1m1s
CI / tests-ui (push) Failing after 3m20s
CI / preflight (push) Skipped
CI / deploy (push) Skipped
The deploy gate ran e2e specs that depend on live content and data, so a missing upload (the /help article images) or a legacy malformed avatar figure could turn a safe code deploy red. Split the suites by what they actually guarantee: - Blocking gate (`pnpm test:e2e`, `playwright.config.ts`): only checks the CMS can guarantee itself — anonymous redirects, register form fields, the captcha DOM contract and the cache-control headers (deterministic origin-direct). - Advisory suite (`pnpm test:e2e:quality`, `playwright.quality.config.ts`): broken images, layout overflow and warm-page latency, which depend on live content/upload state and the host. It runs as a `continue-on-error` CI job against the public site so a real content problem stays visible without blocking the pipeline. Also add `scripts/sync-readme-versions.mjs` (+ tests, docs and a CI check) so the pinned versions in README.md can never drift from package.json / .nvmrc.
59 lines
1.8 KiB
TypeScript
59 lines
1.8 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import {
|
|
expectNoApplicationError,
|
|
expectNoBrokenImages,
|
|
expectNoHorizontalOverflow,
|
|
isMaintenanceRedirect,
|
|
scrollThroughPage,
|
|
} from "../helpers";
|
|
|
|
// ADVISORY suite — run with `pnpm test:e2e:quality`, not part of the deploy
|
|
// gate. These checks depend on live content/upload state and user data (a
|
|
// missing upload, a legacy malformed avatar figure, a bad theme asset), so
|
|
// they are informational: they tell you the site has a real content problem,
|
|
// but they must never block a code deploy. Every assertion the CMS can
|
|
// guarantee on its own lives in the blocking specs instead.
|
|
const PUBLIC_ROUTES = [
|
|
"/",
|
|
"/news",
|
|
"/staff",
|
|
"/shop",
|
|
"/search",
|
|
"/leaderboard",
|
|
"/help",
|
|
"/radio",
|
|
] as const;
|
|
|
|
for (const route of PUBLIC_ROUTES) {
|
|
test(`${route} loads every image and does not overflow`, async ({ page }) => {
|
|
const response = await page.goto(route);
|
|
expect(response?.ok(), `GET ${route} -> ${response?.status()}`).toBe(true);
|
|
|
|
await expect(page.locator("main").first()).toBeVisible();
|
|
await expectNoApplicationError(page);
|
|
|
|
await scrollThroughPage(page);
|
|
await expectNoBrokenImages(page);
|
|
await expectNoHorizontalOverflow(page);
|
|
});
|
|
}
|
|
|
|
test("the register page loads its theme/avatar images", async ({ page }) => {
|
|
const response = await page.goto("/register");
|
|
test.skip(
|
|
isMaintenanceRedirect(page.url()) || response?.status() === 404,
|
|
"register is not reachable on this deploy",
|
|
);
|
|
await scrollThroughPage(page);
|
|
await expectNoBrokenImages(page);
|
|
await expectNoHorizontalOverflow(page);
|
|
});
|
|
|
|
test("the homepage stays usable on a narrow viewport", async ({ page }) => {
|
|
await page.setViewportSize({ width: 390, height: 844 });
|
|
const response = await page.goto("/");
|
|
expect(response?.ok()).toBe(true);
|
|
await expectNoApplicationError(page);
|
|
await expectNoHorizontalOverflow(page);
|
|
});
|