After M5.2 the portal has 10 surfaces. A harness now catches the obvious regressions (auth broken, KC misconfigured, tenant-registry down) before they reach stage. Doesn't replace unit tests — fills the integration-shape gap.
Linked milestone: M5.3
How
Tests assume the dev stack is up (@needs-stack tag in titles). We don't run them headless against a fully wrapped fixture because Keycloak click-throughs in headless mode are flaky enough that they generate more red herrings than real signal.
The OIDC click-through test (signed-in dashboard with product tiles, role-gated nav) is deliberately deferred — it lands when stage has a stable test user + a recorded session storage state file we can replay (M5.x+ when stage is up).
CI e2e job is off by default: vars.RUN_E2E must equal 'true' on the repo for it to fire. make e2e works locally regardless.
pnpm test (vitest) — unaffected, 24 cases still green, 100% src/lib coverage
pnpm build — unchanged
Manual: make e2e end-to-end against the live dev stack — to be run locally; the testing-session for this is what comes next on Sharang's end
Risk
Blast radius: none until RUN_E2E=true is set. The test suite is local-only by default.
What could break:
Playwright + Next.js 16 type fit — verified via pnpm typecheck.
http://acme.localhost:3000 requires that *.localhost resolves to 127.0.0.1 — true on macOS and most modern Linux out of the box. If a tester is on a network that does weird things to .localhost, override PLAYWRIGHT_BASE_URL=http://localhost:3000 and Next's middleware will still handle the slug via the path (modulo subdomain rewrite assertions).
Rollback plan: revert. CI is unaffected by the revert since the e2e job is gated off.
Checklist
Unit tests — n/a (this PR adds tests, not features)
Docs updated (README has an e2e section)
Secrets via Infisical — none needed locally; CI variables documented
Migration — n/a
Tenant scoping — n/a (asserts at the boundary)
CHANGELOG entry under "Added"
## What
M5.3 Playwright e2e harness, scoped to the local dev stack. The CI e2e job is gated behind a `RUN_E2E` repo variable so it stays off until stage exists.
- `playwright.config.ts` — chromium project; baseURL defaults to `http://acme.localhost:3000`.
- `tests/e2e/apex.spec.ts` — landing page renders.
- `tests/e2e/tenant.spec.ts` — signed-out dashboard shows the Sign-in button; unknown slug returns 404.
- `tests/e2e/health.spec.ts` — every dev-stack endpoint reachable (portal Auth.js, tenant-registry `/healthz`, KC realm metadata).
## Why
After M5.2 the portal has 10 surfaces. A harness now catches the obvious regressions (auth broken, KC misconfigured, tenant-registry down) before they reach stage. Doesn't replace unit tests — fills the integration-shape gap.
Linked milestone: **M5.3**
## How
- Tests assume the dev stack is up (`@needs-stack` tag in titles). We don't run them headless against a fully wrapped fixture because Keycloak click-throughs in headless mode are flaky enough that they generate more red herrings than real signal.
- The OIDC click-through test (signed-in dashboard with product tiles, role-gated nav) is deliberately deferred — it lands when stage has a stable test user + a recorded session storage state file we can replay (M5.x+ when stage is up).
- CI e2e job is **off by default**: `vars.RUN_E2E` must equal `'true'` on the repo for it to fire. `make e2e` works locally regardless.
## Test plan
- [x] `pnpm lint` clean
- [x] `pnpm typecheck` clean (tsconfig excludes `tests/e2e` so Playwright + tsc don't fight)
- [x] `pnpm test` (vitest) — unaffected, 24 cases still green, 100% `src/lib` coverage
- [x] `pnpm build` — unchanged
- [ ] Manual: `make e2e` end-to-end against the live dev stack — to be run locally; the testing-session for this is what comes next on Sharang's end
## Risk
**Blast radius:** none until `RUN_E2E=true` is set. The test suite is local-only by default.
**What could break:**
- Playwright + Next.js 16 type fit — verified via `pnpm typecheck`.
- `http://acme.localhost:3000` requires that *.localhost resolves to 127.0.0.1 — true on macOS and most modern Linux out of the box. If a tester is on a network that does weird things to .localhost, override `PLAYWRIGHT_BASE_URL=http://localhost:3000` and Next's middleware will still handle the slug via the path (modulo subdomain rewrite assertions).
**Rollback plan:** revert. CI is unaffected by the revert since the e2e job is gated off.
## Checklist
- [x] Unit tests — n/a (this PR adds tests, not features)
- [x] Docs updated (README has an e2e section)
- [x] Secrets via Infisical — none needed locally; CI variables documented
- [ ] Migration — n/a
- [ ] Tenant scoping — n/a (asserts at the boundary)
- [x] CHANGELOG entry under "Added"
Adds the M5.3 deliverable scoped to local-dev (stage doesn't exist yet,
so the CI e2e job is gated behind the repo variable RUN_E2E='true' —
defaults off).
Layout:
playwright.config.ts chromium project; baseURL defaults to
http://acme.localhost:3000 (subdomain routing
fires). PLAYWRIGHT_BASE_URL / APEX_URL / etc.
env vars override for stage.
tests/e2e/apex.spec.ts landing page renders
tests/e2e/tenant.spec.ts signed-out dashboard shows Sign in
button; unknown slug returns 404
tests/e2e/health.spec.ts every dev-stack endpoint reachable
(portal /api/auth/providers, tenant-
registry /healthz, KC realm metadata)
Run locally with the full dev stack up:
cd platform/orca-platform && make dev-up
cd platform/tenant-registry && make dev
cd platform/portal && make dev
cd platform/portal && make e2e
OIDC click-through not asserted yet — Keycloak in headless mode is
flaky and depends on a stable test-user password. The current gate
(Sign-in button visible) catches the more common 'auth completely
broken' regression; the deeper smoke lands when stage has its own
test fixture.
tsconfig now excludes tests/e2e so vitest + tsc don't fight over
Playwright type imports.
Refs: M5.3
CODEOWNERS rules
requested review from Benjamin_Boenisch 2026-05-19 14:52:28 +00:00
sharang
merged commit 99fe3b55b2 into main2026-05-19 14:53:18 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What
M5.3 Playwright e2e harness, scoped to the local dev stack. The CI e2e job is gated behind a
RUN_E2Erepo variable so it stays off until stage exists.playwright.config.ts— chromium project; baseURL defaults tohttp://acme.localhost:3000.tests/e2e/apex.spec.ts— landing page renders.tests/e2e/tenant.spec.ts— signed-out dashboard shows the Sign-in button; unknown slug returns 404.tests/e2e/health.spec.ts— every dev-stack endpoint reachable (portal Auth.js, tenant-registry/healthz, KC realm metadata).Why
After M5.2 the portal has 10 surfaces. A harness now catches the obvious regressions (auth broken, KC misconfigured, tenant-registry down) before they reach stage. Doesn't replace unit tests — fills the integration-shape gap.
Linked milestone: M5.3
How
@needs-stacktag in titles). We don't run them headless against a fully wrapped fixture because Keycloak click-throughs in headless mode are flaky enough that they generate more red herrings than real signal.vars.RUN_E2Emust equal'true'on the repo for it to fire.make e2eworks locally regardless.Test plan
pnpm lintcleanpnpm typecheckclean (tsconfig excludestests/e2eso Playwright + tsc don't fight)pnpm test(vitest) — unaffected, 24 cases still green, 100%src/libcoveragepnpm build— unchangedmake e2eend-to-end against the live dev stack — to be run locally; the testing-session for this is what comes next on Sharang's endRisk
Blast radius: none until
RUN_E2E=trueis set. The test suite is local-only by default.What could break:
pnpm typecheck.http://acme.localhost:3000requires that *.localhost resolves to 127.0.0.1 — true on macOS and most modern Linux out of the box. If a tester is on a network that does weird things to .localhost, overridePLAYWRIGHT_BASE_URL=http://localhost:3000and Next's middleware will still handle the slug via the path (modulo subdomain rewrite assertions).Rollback plan: revert. CI is unaffected by the revert since the e2e job is gated off.
Checklist
Adds the M5.3 deliverable scoped to local-dev (stage doesn't exist yet, so the CI e2e job is gated behind the repo variable RUN_E2E='true' — defaults off). Layout: playwright.config.ts chromium project; baseURL defaults to http://acme.localhost:3000 (subdomain routing fires). PLAYWRIGHT_BASE_URL / APEX_URL / etc. env vars override for stage. tests/e2e/apex.spec.ts landing page renders tests/e2e/tenant.spec.ts signed-out dashboard shows Sign in button; unknown slug returns 404 tests/e2e/health.spec.ts every dev-stack endpoint reachable (portal /api/auth/providers, tenant- registry /healthz, KC realm metadata) Run locally with the full dev stack up: cd platform/orca-platform && make dev-up cd platform/tenant-registry && make dev cd platform/portal && make dev cd platform/portal && make e2e OIDC click-through not asserted yet — Keycloak in headless mode is flaky and depends on a stable test-user password. The current gate (Sign-in button visible) catches the more common 'auth completely broken' regression; the deeper smoke lands when stage has its own test fixture. tsconfig now excludes tests/e2e so vitest + tsc don't fight over Playwright type imports. Refs: M5.3