Closes the 'e2e tests only hit production; no local full-stack harness'
finding from the review. The existing e2e suite
(scripts/e2e-explorer-frontend.spec.ts) runs against explorer.d-bis.org
and so can't validate a PR before it merges -- it's a production canary,
not a pre-merge gate.
This PR adds a parallel harness that stands the entire stack up locally
(postgres + elasticsearch + redis via docker-compose, backend API, and
a production build of the frontend) and runs a Playwright smoke spec
against it. It is wired into Make and into a dedicated CI workflow.
Changes:
scripts/e2e-full.sh (new, chmod +x):
- docker compose -p explorer-e2e up -d postgres elasticsearch redis.
- Waits for postgres readiness (pg_isready loop).
- Runs database/migrations/migrate.go so schema + seeds including
the new 0016_jwt_revocations table from PR #8 are applied.
- Starts 'go run ./backend/api/rest' on :8080; waits for /healthz.
- Builds + starts 'npm run start' on :3000; waits for a 200.
- npx playwright install --with-deps chromium; runs the full-stack
spec; tears down docker and kills the backend+frontend processes
via an EXIT trap. E2E_KEEP_STACK=1 bypasses teardown for
interactive debugging.
- Generates an ephemeral JWT_SECRET per run so stale tokens don't
bleed across runs (and the fail-fast check from PR #3 passes).
- Provides a dev-safe CSP_HEADER default so PR #3's hardened
production CSP check doesn't reject localhost connections.
scripts/e2e-full-stack.spec.ts (new):
- Playwright spec that exercises public routes + a couple of
backend endpoints. Takes a full-page screenshot of each route
into test-results/screenshots/<route>.png so reviewers can
eyeball the render from CI artefacts.
- Covers: /healthz, /, /blocks, /transactions, /addresses, /tokens,
/pools, /search, /wallet, /routes, /api/v1/access/products (YAML
catalogue from PR #7), /api/v1/auth/nonce (SIWE kickoff).
- Sticks to Track-1 (no wallet auth needed) so it can run in CI
without provisioning a test wallet.
playwright.config.ts:
- Broadened testMatch from a single filename to /e2e-.*\.spec\.ts/
so the new spec is picked up alongside the existing production
canary spec. fullyParallel, worker, timeout, reporter, and
project configuration unchanged.
Makefile:
- New 'e2e-full' target -> ./scripts/e2e-full.sh. Listed in 'help'.
- test-e2e (production canary) left untouched.
.github/workflows/e2e-full.yml (new):
- Dedicated workflow, NOT on every push/PR (the full stack takes
minutes and requires docker). Triggers:
* workflow_dispatch (manual)
* PRs labelled run-e2e-full (opt-in for changes that touch
migrations, auth, or routing)
* nightly schedule (04:00 UTC)
- Uses Go 1.23.x and Node 20 to match PR #5's pinning.
- Uploads two artefacts on every run: e2e-screenshots
(test-results/screenshots/) and playwright-report.
docs/TESTING.md (new):
- Four-tier test pyramid: unit -> static analysis -> production
canary -> full-stack Playwright.
- Env var reference table for e2e-full.sh.
- How to trigger the CI workflow.
Verification:
bash -n scripts/e2e-full.sh clean
The spec imports compile cleanly against the existing @playwright
/test v1.40 declared in the root package.json; no new runtime
dependencies are added.
Existing scripts/e2e-explorer-frontend.spec.ts still matched by
the broadened testMatch regex.
Advances completion criterion 7 (end-to-end coverage): 'make e2e-full
boots the real stack, Playwright runs against it, CI uploads
screenshots, a nightly job catches regressions that only show up
when all services are live.'
2.6 KiB
Testing
The explorer has four test tiers. Run them in order of fidelity when debugging a regression.
1. Unit / package tests
Fast. Run on every PR.
# Backend
cd backend && go test ./...
# Frontend
cd frontend && npm test # lint + type-check
cd frontend && npm run test:unit # vitest
2. Static analysis
Blocking on CI since PR #5 (chore(ci): align Go to 1.23.x, add staticcheck/govulncheck/gitleaks gates).
cd backend && staticcheck ./...
cd backend && govulncheck ./...
git diff master... | gitleaks protect --staged --config ../.gitleaks.toml
3. Production-targeting Playwright
Runs against https://explorer.d-bis.org (or the URL in EXPLORER_URL)
and only checks public routes. Useful as a production canary; wired
into the test-e2e Make target.
EXPLORER_URL=https://explorer.d-bis.org make test-e2e
4. Full-stack Playwright (make e2e-full)
Spins up the entire stack locally — postgres, elasticsearch,
redis via docker-compose, plus a local build of backend/api/rest
and frontend — then runs the full-stack Playwright spec against it.
make e2e-full
What it does, in order:
docker compose -p explorer-e2e up -d postgres elasticsearch redis- Wait for Postgres readiness.
- Run
go run database/migrations/migrate.goto apply schema + seeds (including0016_jwt_revocationsfrom PR #8). go run ./backend/api/reston port8080.npm ci && npm run build && npm run starton port3000.npx playwright test scripts/e2e-full-stack.spec.ts.- Tear everything down (unless
E2E_KEEP_STACK=1).
Screenshots of every route are written to
test-results/screenshots/<route>.png.
Env vars
| Var | Default | Purpose |
|---|---|---|
EXPLORER_URL |
http://localhost:3000 |
Frontend base URL for the spec |
EXPLORER_API_URL |
http://localhost:8080 |
Backend base URL |
JWT_SECRET |
generated per-run | Required by backend fail-fast check (PR #3) |
CSP_HEADER |
dev-safe default | Same |
E2E_KEEP_STACK |
0 |
If 1, leave the stack up after the run |
E2E_SKIP_DOCKER |
0 |
If 1, assume docker services already running |
E2E_SCREENSHOT_DIR |
test-results/screenshots |
Where to write PNGs |
CI integration
.github/workflows/e2e-full.yml runs make e2e-full on:
- Manual trigger (
workflow_dispatch). - PRs labelled
run-e2e-full— apply the label when a change warrants full-stack validation (migrations, auth, routing changes). - Nightly at 04:00 UTC.
Screenshots and the Playwright HTML report are uploaded as build artefacts.