Skip to content

Web e2e smoke (Playwright) + pending branch work - #14

Merged
JasonPaff merged 16 commits into
mainfrom
more-updates
Jul 3, 2026
Merged

JasonPaff merged 16 commits into
mainfrom
more-updates

Conversation

@JasonPaff

Copy link
Copy Markdown
Owner

Summary

Lands add-web-e2e-smoke (audit item 15, second half): the repo's first e2e layer — a Playwright smoke in apps/web/e2e/ that signs in through real Clerk, hits Quick Play, reaches the live table, completes the shuffle handshake, and plays a full hand to its conclusion against the real four-service stack.

  • Auth: @clerk/testing with an ephemeral per-run test user (created via the Backend API in global setup, deleted in a teardown project, stale orphans swept). Per-run identities eliminate leftover-live-match contention between runs — a shared user blocked consecutive runs for ~8 minutes while bots played out its abandoned match.
  • Stack: Playwright webServer attaches to a running local stack, boots it in CI. New unauthenticated GET /healthz routes on match + bots serve as readiness URLs (api reuses its tRPC health query; web probes /sign-in).
  • Hand loop: strategy-free — pass every auction turn, declare an accepted suit when dealer-forced in by the all-pass rule (observed in practice), click cards until accepted during trick play.
  • CI: new non-blocking E2E workflow on PRs (E2E_* repo secrets → root .env). Deliberately NOT in the main ruleset's required checks; promote via a one-line ruleset edit after a stable stretch (~2 weeks).
  • Unit gate untouched: vitest excludes e2e/**; turbo run test collects zero Playwright specs.

This branch also carries the previously unmerged work: web vitest foundation (add-web-test-foundation), root .env auto-load, pnpm catalog, audit doc updates.

Test plan

  • Smoke green twice consecutively against a running local stack (48s / 43s)
  • Bad-credential run fails fast in global setup with an auth-attributable error
  • pnpm lint / typecheck / test green; unit runner collects no e2e specs
  • This PR's own E2E workflow run is the first live CI execution — iterate here until green

🤖 Generated with Claude Code

JasonPaff and others added 6 commits July 2, 2026 23:11
Single-source the 7 hand-duplicated tool versions (typescript, eslint,
vitest, @types/node, tsx, tsup, drizzle-orm) via a pnpm workspace
catalog in pnpm-workspace.yaml; drizzle-orm had already drifted across
three manifests (^0.45.2 vs a bare pin).

Also remove the no-op "build": "tsc --noEmit" script from the four
internal packages (bots, engine, fairness, shared) so `turbo run build`
only runs the apps' real builds and stops double type-checking every
package in CI.
Add loadLocalEnv() (packages/shared/src/server/env/local.ts) which
hydrates process.env from the repo-root .env at boot: dev-only
(no-op when NODE_ENV is production/test) and never overrides an
already-set variable. api, match, and bots each call it before
loading their own validated env, so a plain root `pnpm dev` boots the
whole stack with no exported shell vars.

Since one .env now feeds all three long-lived services at once, PORT
must stay unset there or every service would bind the same port. The
PORT schema treats an empty string as unset, falling through to each
service's own default (api 3001, match 2567, bots 2568); a real PORT
env var still overrides for a single process.
Records the direct commits (no OpenSpec change) for the turbo
build/typecheck split, the pnpm catalog, and root .env auto-loading
for local dev; also drops the stale "P1 complete except item 9" note
from item 14 now that item 9 (bot-service integration) is archived.
Adds vitest + testing-library harness to apps/web (jsdom env, fake
Colyseus client injected through ColyseusProvider's new `client` prop)
and covers the use-table-connection reconnect machine plus table-store
derivation logic with unit tests. table-store exports buildRenderModel
and deriveAvailableAction so tests can exercise them directly.

Archives the add-web-test-foundation OpenSpec change and marks item 15
in the hardening audit as half done, with the Playwright e2e smoke
left as a follow-up.
Audit item 15's second half (change add-web-e2e-smoke): a Playwright suite
in apps/web/e2e/ proving the signed-in happy path end to end — hall →
Quick Play → live table → shuffle handshake → a full hand played to its
conclusion — against the real web+api+match+bots stack.

- Clerk auth via @clerk/testing: each run creates an ephemeral test user
  (Backend API), signs it in server-side in global setup, persists storage
  state, and deletes the user in a teardown project; stale orphans are
  swept at the next run's setup. Per-run identities avoid the leftover
  live-match contention a shared user hits (bots play an abandoned match
  out for ~8 minutes).
- webServer boots/attaches to the four services; new unauthenticated
  GET /healthz liveness routes on match and bots (api reuses its tRPC
  health query; web probes /sign-in, the one unprotected route).
- The hand loop is strategy-free: pass every auction turn, declare an
  accepted suit if dealer-forced in (all-pass rule), click cards until
  accepted on trick-play turns (reject+resync makes wrong clicks
  harmless).
- New non-blocking e2e.yml workflow on PRs (E2E_* repository secrets →
  root .env, the contract the services already read); not in the main
  ruleset's required checks — promotion is a later ruleset edit.
- vitest excludes e2e/** so the unit gate is untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 3, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
meld-rank-web Ready Ready Preview, Comment Jul 3, 2026 3:50pm

`next dev` rejects an empty PORT env var (the root .env deliberately ships
`PORT=` empty for the Node services, whose schema treats empty as unset) —
the Playwright config inherited it via loadLocalEnv and every CI boot died
instantly. Also pipe webServer stdout so boot failures are diagnosable in
CI logs, and exempt the Node-only Playwright harness from the web
browser-bundle import guard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
JasonPaff added 8 commits July 3, 2026 09:45
Add an end-to-end Playwright test in `apps/web/e2e/` to validate the signed-in happy path: hall → Quick Play → live table → shuffle handshake → full hand completion. Includes:

- Ephemeral Clerk test user setup via `@clerk/testing`, with session persistence and teardown.
- Playwright `webServer` boots/attaches to the local stack, probing health endpoints.
- Strategy-free hand completion logic (pass auction turns, declare trump if forced in, play any legal card).
- Separate non-blocking CI workflow (`e2e.yml`) with Playwright artifacts uploaded on failure. Workflow runs on PRs and uses `E2E_*` secrets for dev-resource provisioning.

Unit testing remains unaffected (`vitest` excludes `e2e/**`). The smoke test is not a required check yet, awaiting stability observations.
…ions

Resolve the polish-engine-correctness change: royal-marriage melds now
record the physical card copies a run did not consume (copyIndex-based),
so identity-based bury exclusions no longer miss or double-count cards.

Add reduceWithVerdict alongside reduce, projecting a typed RejectionCode
(wrong-phase, out-of-turn, illegal-bid, unknown-suit, card-not-held,
illegal-card, illegal-bury, no-forced-move, config-fault) instead of
silently returning the unchanged state, while reduce stays its exact
.state projection so replay behavior is unchanged.

Prove timeout escape completeness end-to-end with a 32-seed x 2-variant
match-fold property test, and bump ENGINE_VERSION to 0.1.0 as the
replay-compatibility stamp for the meld attribution change.
Extract the four-suit tuple into variant/suits.ts and reuse it from
schema.ts, canonical.ts, and meld-table.ts instead of three copies.
Remove exports with no remaining callers: pingRedis, widowEnabled/
buryEnabled/passingEnabled, TRACE_ID_FIELD, and PACKAGE_NAME. Un-barrel
canonicalJson from the variant surface, and update stale doc comments
(errors.ts, db/client.ts, trace.ts) to match current behavior.
…it scan

Export applyDealWithRng and startNextHandBase from the reducer so the
match room's deal.ts becomes a thin adapter over the engine's own
orchestration instead of re-implementing phase-advance and hand-boundary
logic locally. Reuse the shared SUITS tuple in meld.ts instead of a local
copy. Update the hand-lifecycle-state-machine and match-shuffle-handshake
specs to describe the engine-owned seam, and add dealOrchestration.test.ts
covering it.
…lyph

Introduce PageShell/CenteredMessage to replace the duplicated <main>
shell markup across the landing, sign-in/up, table, and waiting-room
pages. Add a createStoreContext factory and rebuild SessionStore/
TableStore on top of it, removing duplicated Provider/useContext
boilerplate. Add useTableHandoff to dedupe the handoff-to-table logic
shared by casual-hall and use-waiting-room. Extract SUIT_GLYPH into
suit-glyph.ts so card.tsx and table-view.tsx share one copy, and use
cardIdentityKey for the card list key instead of a hand-rolled string.
Also fixes a stale doc comment in env.ts now that the Clerk publishable
key is required.
…ckerfile

Replace the three near-identical apps/*/Dockerfile files with a single
parameterized root Dockerfile that selects the service via PKG/APP_DIR
build args. Each fly.toml's [build] section now points at the root
Dockerfile and supplies its own args, so deploy.yml no longer passes
--dockerfile and a base-image or build-pipeline change is made exactly
once. Update infra/README.md and the deployment-config spec to match.
Archive the completed prune-and-dedupe-hygiene change and mark item 19 of
the hardening audit done, closing out the last remaining audit item.
@JasonPaff
JasonPaff merged commit fe81c00 into main Jul 3, 2026
4 checks passed
@JasonPaff
JasonPaff deleted the more-updates branch July 3, 2026 15:52
JasonPaff added a commit that referenced this pull request Jul 3, 2026
…res (#15)

The PR #14 merge exposed two resource-exhaustion failures that never hit
PR runs:

- Deploy: all three Fly apps built concurrently on the shared remote
  builder and api/match were OOM-killed (exit 137) in pnpm deploy.
  Serialize the matrix with max-parallel: 1.
- CI: the lockfile change invalidated every turbo hash, so main ran all
  25 tasks cold at default concurrency 10 and a vitest worker was killed.
  Cap the quality gate at --concurrency=4 to match runner cores.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — aa97f64a Deployed Jul 3, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant