play_canvas.spec.js covers the window.__FERROUS_DEBUG__ bridge on the
/play route (five tests): bridge availability + seed param, draw3 URL
param, applyLegalMove/undo round-trip, failureReport schema, and
autonomous autoplay invariant batch across 7 seeds.
All tests drive exclusively through the debug bridge — no DOM selectors,
because the Bevy canvas is a single <canvas> element with no HTML
controls.
Also update SESSION_HANDOFF.md to reflect post-v0.35.1 work (10 commits
since 2026-05-18 handoff), new e2e architecture notes, and HiDPI fix doc.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
solitaire_server/e2e/:
- smoke.spec.js: verifies /play-classic loads, exposes window.__FERROUS_DEBUG__
bridge, keyboard parity (Space=draw, U=undo), debug failure report, and
replay payload builder exports schema-v2 moves.
- gameplay_review.spec.js: HUD/controls render check, stock-click + undo
player flow, draw-mode toggle, autonomous play invariant batch, and
cycle-detection regression guard.
- cycle_metrics.js: headless cycle-rate analysis tool; run via
`npm run review:cycles` with configurable policy, game count, and
thresholds. Regression gate baked into package.json scripts.
- playwright.config.js: targets the local server at http://localhost:8080.
- package.json / package-lock.json: @playwright/test 1.60.0.
.gitea/workflows/web-e2e.yml:
- Runs on pushes to solitaire_server/, solitaire_wasm/, solitaire_core/,
or Cargo changes. Starts the server binary, waits for /health, runs
the full Playwright suite, uploads test-results/ on failure.
docs/testing-architecture.md: documents the three-tier test strategy
(unit → Playwright smoke → cycle regression) and the __FERROUS_DEBUG__
bridge contract.
scripts/update_quaternions_deps.sh: helper to bump the Quaternions
registry deps (klondike, card_game) by version and run the full
safety gate including deterministic replay checks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>