Testing Guide
Testing Guide
Tests run on Vitest (jsdom environment). 50 tests live in
src/__tests__/.
cd games
npm test # run once (CI uses this)
npm run test:watch # watch mode
What’s covered
| File | Focus |
|---|---|
rng.test.ts |
Seed determinism, ranges, shuffle immutability, getState round-trip. |
match.test.ts |
createMatch, turn progression, illegal/out-of-turn rejection, terminal state, legalActions/botAction. |
cards.test.ts |
Deck integrity, deterministic shuffle, dealing, immutable zone ops. |
board.test.ts |
Neighbours, BFS reachability (incl. dynamic blockers), distances, track wrap/clamp. |
serialize.test.ts |
Round-trip, corrupt/missing/newer-schema rejection. |
client.test.ts |
Dispatch + notify, undo/redo, stale-snapshot guard in replaceState. |
crown-rush.test.ts |
Deal counts, draw→discard flow, win on three of a kind, illegal sequences. |
lantern-hunt.test.ts |
Roll→move, reachable rejection, third-lantern win. |
relic-run.test.ts |
Phase gating, pass/turn flow, Ward card → fourth relic win. |
app.test.tsx |
Gallery lists all games; setup screen renders; every game view mounts without crashing. |
Testing strategy
- Pure engine = easy tests. Because
applyActionis a pure function, most tests arestate → action → assert. No mocks, no DOM. - Determinism via fixed seeds. Pass
seedtocreateMatchand assert on the resultinggameto lock behaviour without flakiness. - Craft terminal states. To test a win without playing a whole game, build a
match then spread-override
state.game(andstate.turnfor phase) into the exact pre-win situation, then dispatch the finishing action. See the demo tests for the pattern. - Firebase boundary. The Firebase adapter is exercised through the
SyncAdapterinterface; the local adapter is the concrete implementation used in tests/dev. Real RTDB isn’t required locally — stub the adapter to test room flows in isolation if needed.
Adding tests for a new game
Mirror a demo test: assert setup shape, one happy-path turn, one rejected
illegal action, and one crafted win. Keep states JSON-plain so toEqual works.