test(e2e): make Playwright browser/UI testing a mandatory CI gate#102
test(e2e): make Playwright browser/UI testing a mandatory CI gate#102mastermanas805 wants to merge 1 commit into
Conversation
A dashboard change could previously ship having broken login, claim, the dashboard, or the payments/upgrade flow — the Playwright suite covered none of those money-critical paths. This makes browser/UI testing a hard, hermetic gate so a UI regression fails CI before it can merge. Coverage closed (vs the Chrome-MCP S1–S8 test plan): - S5 Payments (headline): upgrade-journey.spec.ts — checkout success → Razorpay redirect, checkout failure (500 / 503 billing_not_configured / 409 already_on_plan), the Change-plan modal (immediate / short_url / already_on_plan / 5xx support-fallback), invoice rendering with null/pending/unknown-status rows (the "$NaN / Invalid Date" regression), the Annual toggle, and the no-self-serve-cancel policy. - S3 Claim: claim-flow.spec.ts — preview, single-use 409, post-claim payment funnel + countdown, expired token, funnel→Razorpay CTA. - S4 Dashboard: dashboard-trust.spec.ts — render, empty state, the 429 retry-hint UI, and Overview-tile ⇄ Billing-panel deployment-count consistency (the S5-F4 drift). - S2 Auth: auth-guards.spec.ts — every /app/* route bounces unauthed to /login, and the checkout deep-link intent survives the login bounce. All API + Razorpay traffic is page.route()-mocked (VITE_NO_PROXY=1) so the suite is hermetic and deterministic — it creates nothing on any backend and needs no teardown. The Razorpay short_url is a fake and is itself intercepted; the browser never loads a real checkout page. CI gate: the `playwright` job is renamed to `playwright (mandatory UI gate)`, runs `npm run test:e2e:ci` (the exact local equivalent), and uploads the HTML report + traces as an artifact on failure. For the gate to BLOCK a PR, the operator must add this check to the branch-protection rule for `main`. Suite: 23 → 57 Playwright tests. tsc/build/vitest unaffected (662 pass). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
93f784b to
e6514a5
Compare
|
Rebase attempt 2026-05-20 hit conflicts. Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com |
Status check 2026-05-20 — still adds valueAudit against current main ( Main's
Main's Not replaced by INTEGRATION-TESTS-2026-05-20.md — that work covers api/worker/provisioner Go integration (backup/restore, Brevo webhook, propagation runner, deep /readyz). Disjoint from UI testing. Mergeability: Branch-protection operator action (carry-over from PR body): for the Recommendation: merge. PR holds up against current main; coverage 23 → 57 tests is exactly the money-critical UI surface not otherwise gated. |
|
CI is green. Cannot auto-merge via this session — the PR touches |
Why
A dashboard change could previously ship having silently broken login, claim, the dashboard, or the payments/upgrade flow — the Playwright suite covered none of those money-critical user paths. This makes browser/UI testing a hard, hermetic CI gate so a UI regression fails before it can merge.
Coverage gaps found & closed
Audited the existing 23-test Playwright suite against the Chrome-MCP
CHROME-MCP-TEST-PLAN-2026-05-19.md(S1–S8). Critical gaps: S5 Payments had zero automation (and the Chrome-MCP S5 run is itself blocked in prod — Razorpay isn't recurring-enabled), S3 Claim had zero coverage, and S4 had no 429 / deployment-count-consistency checks.New specs (
e2e/):upgrade-journey.spec.ts(S5, headline) — checkout success → Razorpay redirect; checkout failure (500 / 503billing_not_configured/ 409already_on_plan); Change-plan modal (immediate / short_url / already_on_plan / 5xx → support-fallback); invoice rendering with null/pending/unknown-status rows (the S5-F3$NaN/Invalid Dateregression); Annual toggle; no-self-serve-cancel policy.claim-flow.spec.ts(S3) — preview, single-use 409 replay, post-claim payment funnel + countdown, expired token, funnel→Razorpay CTA.dashboard-trust.spec.ts(S4/S8) — dashboard render, empty state, the 429 retry-hint UI, and Overview-tile ⇄ Billing-panel deployment-count consistency (the S5-F4 drift).auth-guards.spec.ts(S2) — every/app/*route bounces an unauthed visitor to/login; the checkout deep-link intent survives the login bounce.e2e/fixtures.tsgains billing fixtures +installBillingAPIFake/mockCheckout*/mockChangePlanhelpers.Hermetic — creates nothing
All API + Razorpay traffic is
page.route()-mocked (VITE_NO_PROXY=1, per CLAUDE.md convention 10). The suite is deterministic, creates nothing on any backend, and needs no teardown. The Razorpayshort_urlis a fake and is itself intercepted — the browser never loads a real checkout page. No test hits a real backend; if one ever did it would have to teardown.CI gate: advisory → blocking
playwrightjob is renamed toplaywright (mandatory UI gate)and runsnpm run test:e2e:ci(the exact local equivalent — new script).playwright (mandatory UI gate)to the branch-protection rule formain(Settings → Branches → Require status checks). The workflow makes the check available; the rule makes it required.Suites: Playwright vs Chrome-MCP
CHROME-MCP-TEST-PLAN-2026-05-19.mdis updated to a living two-layer map — Playwright = the automated must-pass gate, Chrome-MCP = the manual exploratory layer for what Playwright can't do hermetically (real Razorpay/OTP/decline, real provisioning, Lighthouse).Gate output
npx tsc --noEmitclean ·npm run build(incl. prerender) OK ·npx vitest run662 pass ·npx playwright test --project=chromium57 pass (was 23).🤖 Generated with Claude Code