@umbraculum/web-e2e
Deterministic, headless end-to-end tests for apps/web (Playwright). Run via the official Playwright Docker image so the suite never depends on host npm or system Chromium.
[!NOTE] Part of Umbraculum — an open-source toolset for building workspace-shaped operational applications.
What this is
The web app's end-to-end test suite. It exercises real user flows against a fully-running stack — the apps/web Next.js server, the services/api Fastify service, and the Postgres primary/replica via pgpool — using deterministic seeded fixtures (@umbraculum/web-e2e shares persona definitions with services/api/src/cli/seedE2eFixture.ts). The suite runs in a one-shot Playwright container against the dev stack via --network host, which keeps docker-compose.yml untouched per the plugin-shipped 00-shared-no-unilateral-runner-compose-changes.mdc rule. See docs/TESTING.md for the platform-wide test layer map.
Folder taxonomy (RFC-0011 Wave 5): specs mirror product layers — platform/ (auth, workspace, dashboard, AI), canonical/ (MRP/CRP alpha), verticals/brewery/ (recipes, water, brew-day).
Scope
- Contains: cross-page user-flow specs (platform, canonical, verticals-brewery projects), persona-aware Playwright fixtures, centralized role/label locators (per the accessibility mandate in
docs/DEVELOPMENT-ACCESSIBILITY.md), axe-core a11y helpers, persisted per-persona storage state, HTML reporter wiring. - Does not contain: API-level integration tests (those live in
services/api/src/tests/), unit tests (vitest in each workspace), theservices/apiE2E seed itself (lives inservices/api/src/cli/seedE2eFixture.ts— this suite consumes its output), Cypress / Selenium / WebdriverIO harness code (the project standardized on Playwright; seedocs/TESTING.md).
Quick gates before Playwright
Run from repo root in order before any Playwright invocation (platform, canonical, verticals-brewery). Stop on the first failure.
docker compose up -d api web gotenberg redis # gotenberg+redis required for export/render specs
./scripts/smoke.sh
curl -sf http://localhost:18080/api/health | grep -q '"ok":true' \
|| { echo "FAIL: API unhealthy (502?)"; exit 1; }
curl -sf -o /dev/null -w '%{http_code}\n' http://localhost:18080/en/login | grep -q '^200$' \
|| { echo "FAIL: web login not 200 (500?)"; exit 1; }
docker compose exec api npm run seed:e2e
# After stack recovery: rm -f apps/web/e2e/.auth/e2e-admin.json
MRP/CRP export troubleshooting (502/500/seed/password): docs/design/mrp-crp-alpha-demo-walkthrough.md. Platform layer map: docs/TESTING.md § L5.
Quick start
Prereqs: complete Quick gates above.
Run the full suite from repo root:
docker run --rm --network host \
-e E2E_BASE_URL=http://localhost:18080 \
-v "$PWD/apps/web/e2e:/e2e" \
-w /e2e \
mcr.microsoft.com/playwright:v1.60.0-noble \
bash -lc "npm install --no-audit --no-fund && npx playwright test"
Single project (platform only):
docker run --rm --network host \
-e E2E_BASE_URL=http://localhost:18080 \
-e E2E_ADMIN_PASSWORD="${E2E_ADMIN_PASSWORD:-e2e-admin-pw!}" \
-v "$PWD/apps/web/e2e:/e2e" \
-w /e2e \
mcr.microsoft.com/playwright:v1.60.0-noble \
bash -lc "npm install --no-audit --no-fund && npx playwright test --project=platform"
MRP/CRP export only (canonical/b2b-registered-mrp-crp-export-alpha.spec.ts — needs gotenberg + redis):
docker run --rm --network host \
-e E2E_BASE_URL=http://localhost:18080 \
-e E2E_ADMIN_PASSWORD="${E2E_ADMIN_PASSWORD:-e2e-admin-pw!}" \
-v "$PWD/apps/web/e2e:/e2e" \
-w /e2e \
mcr.microsoft.com/playwright:v1.60.0-noble \
bash -lc "npm install --no-audit --no-fund && npx playwright test --project=canonical canonical/b2b-registered-mrp-crp-export-alpha.spec.ts --workers=1"
Per-project shortcuts (from apps/web/e2e/ after npm install):
npm run test:platform # --project=platform
npm run test:canonical # --project=canonical
npm run test:verticals-brewery # --project=verticals-brewery
npm run test:all # all three projects
Deprecated aliases: test:smoke runs all projects (formerly smoke-only); test:brewday → test:verticals-brewery.
Open the HTML report (after a run):
docker run --rm --network host \
-v "$PWD/apps/web/e2e:/e2e" -w /e2e \
mcr.microsoft.com/playwright:v1.60.0-noble \
npx playwright show-report
Layout
| Path | Purpose |
|---|---|
playwright.config.ts | projects (platform, canonical, verticals-brewery), reporters, trace/screenshot policy |
personas.json | single source of truth for E2E personas + fixture IDs (mirrors services/api/src/cli/seedE2eFixture.ts) |
support/personas.ts | persona loader + storage-state path |
support/locators.ts | centralized role/label locators (per the accessibility mandate) |
support/auth-fixture.ts | per-persona authenticatedContext / authenticatedPage Playwright fixture |
support/axe.ts | axe-core helper: expectNoCriticalA11yViolations |
platform/*.spec.ts | platform flows (auth, select-workspace, dashboard, ai-pages) |
canonical/*.spec.ts | canonical module alpha (MRP/CRP read-only + export) |
verticals/brewery/*.spec.ts | reference vertical (recipes, water, brew-day) |
.auth/<persona>.json | persisted storageState per persona (gitignored) |
Rule 63 b2c/b2b filename prefixes: Done (2026-06-07 backlog) — specs use b2b-registered-<action>.spec.ts (workspace SaaS; authenticated persona flows).
Build / test / lint (local)
- Test (full suite): see Quick start above. Always run from repo root.
- Test (single spec): e.g.
npx playwright test platform/b2b-registered-auth.spec.tsin the docker invocation. - Trace inspection: when a spec fails,
test-results/<test-name>/trace.zipis produced; open with theplaywright show-traceroute in Quick start. - Typecheck: handled by the per-workspace typecheck CI gate; see
docs/TYPING.md§"Per-workspace CI gate" (this workspace landed in Phase 5, commitaab5b41). - Container-only execution: per the
node-npm-container-onlyskill shipped byumbraculum-node-react-cursor-assistant, the suite never runs against host Node / npm / Chromium.
How it fits in
- Consumed by: CI (the typecheck workflow
.github/workflows/typecheck.yml); developer machines for local regression validation; nightly E2E triage per the plugin-shipped62-nightly-e2e-unattended.mdcworkflow rule. - Depends on: a running dev stack (
docker compose up -d); the seeded fixture output ofservices/api'sseed:e2escript; persona definitions kept in sync withservices/api/src/cli/seedE2eFixture.ts. - Naming convention: specs follow the plugin-shipped
63-e2e-test-naming-convention.mdcrule —b2b-registered-<action>.spec.tsfor authenticated workspace flows.
Notes
docker-compose.ymlis not modified by anything in this suite (the plugin-shipped00-shared-no-unilateral-runner-compose-changes.mdcrule applies).- Persona passwords default to the values in
personas.json; override viaE2E_ADMIN_PASSWORD/E2E_MEMBER_PASSWORD/E2E_VIEWER_PASSWORDenv vars. The apiseed:e2escript hashes the same env vars — if login times out in Playwright, confirm seed ran and pass-e E2E_ADMIN_PASSWORD=…into the Playwrightdocker runto match the api container. Delete staleapps/web/e2e/.auth/<persona>.jsonafter a password change. - The suite's tier marker is implicit (Tier: Public via the standard, since the README is part of the public-flip surface — see
docs/DOCS-README-STANDARDS.md).
Status
Eleven specs across three Playwright projects (platform, canonical, verticals-brewery). Coverage of billing flows and second-vertical configurations is on the H1 2027 trajectory per docs/ROADMAP.md; the existing harness (personas, fixtures, locators, axe) is shaped to absorb those flows without architectural changes.
Further reading
docs/TESTING.md— platform-wide test layer map (unit / integration / contract / E2E)docs/design/pre-flip-application-surface-backbone.md§5 — E2E taxonomydocs/PLATFORM-ARCHITECTURE.md— platform vision and module boundariesdocs/DOCS-README-STANDARDS.md— module README standard this file conforms todocs/DEVELOPMENT-ACCESSIBILITY.md— accessibility constraints (a11y is a hard requirement; the suite enforces it viasupport/axe.ts)