test(ci): deterministic deploy gate + advisory quality suite; sync README versions
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.
This commit is contained in:
openhands committed 2026-10-15 16:26:47 +02:00
1 parent ef2f8c30f0
commit ef6c671903
12 files changed
+419 -48

No files matched your search

+6 -23
View File
@@ -1,28 +1,11 @@
import { expect, test } from "@playwright/test";
// Latency + caching contract for the anonymous pages. The perf work relies on
// the edge/shared cache (`src/proxy.ts`): public content pages advertise a
// short `s-maxage`, while session-dependent pages (login, register, settings)
// must stay `private, no-store`. Budgets are deliberately loose so a cold
// cache or a slow CI hop does not flap the gate.
const BUDGET_MS = Number(process.env.E2E_LOAD_BUDGET_MS || 4000);
const WARM_ROUTES = ["/", "/news", "/staff", "/shop", "/login", "/register"];
for (const route of WARM_ROUTES) {
test(`${route} responds within the warm budget`, async ({ request }) => {
await request.get(route); // warm the render + data caches
const started = Date.now();
const response = await request.get(route);
const elapsed = Date.now() - started;
expect([200, 304]).toContain(response.status());
expect(
elapsed,
`GET ${route} took ${elapsed}ms (budget ${BUDGET_MS}ms)`,
).toBeLessThan(BUDGET_MS);
});
}
// Caching contract for the anonymous pages. This is deterministic and stays in
// the blocking deploy gate: the perf work relies on the edge/shared cache
// (`src/proxy.ts`) — public content pages advertise a short `s-maxage`, while
// session-dependent pages (login, register, settings) must stay
// `private, no-store`. Timing budgets are advisory and live in
// `e2e/quality/performance.spec.ts`.
test("anonymous content pages advertise a shared cache", async ({
request,
}) => {