Files
JoshHeaps.Net/tests/holdem
jheapsandClaude Opus 5 a488bbf832 Stop rebuilding the hand log after every fold, call and raise
Profiled a long night at a full table — 24 seats, 200 logged hands — because
that's the state the tool is slowest in and the one a dealer reaches at 2am.

A full re-render cost 30ms, and it runs after every single action. Broken down,
25.7ms of that was renderHandHistory: tearing down and rebuilding 200 rows of a
panel that hadn't changed and that nobody is looking at mid-hand. Everything
else on the table put together came to about 4ms.

The log only changes when a hand is settled or the history is cleared — maybe
once every thirty taps. It now carries a cheap signature (length, hand counter,
and the newest row) and is skipped when that hasn't moved. Entries are immutable
once written and only ever added at the front, so the signature catches a
recorded hand, a cleared history, and an undo that puts a hand back.

    renderAll, every action     30.07ms -> 4.18ms
    renderHandHistory, skipped  25.74ms -> 0ms
    renderHandHistory, rebuild  25.74ms -> 9.05ms

The rebuild got faster too, for the times it does run — once per hand, where
25ms of jank lands exactly on the "next hand" tap. toLocaleTimeString was the
single most expensive call in the loop and a logged hand's timestamp never
changes, so the formatted string is kept; and the rows are built into a fragment
so the panel lays out once instead of two hundred times.

A cache like this is only worth having if it can't go stale — a dealer reading
last hand's payouts while settling this one is worse than a slow panel. 10 tests
cover the invalidation directly: unchanged through a street of betting, changed
by settling, by clearing, by an undo back to a shorter log, by two hands that
differ only in the pot, and by the counter moving on.

Validated with Playwright against the real page: the rendered rows match the
stored history through settling a hand in the wizard, undoing it, clearing the
log and recording again. Touch and layout guarantees from the earlier rounds
still hold — 0 of 87 controls on touch-action auto, 0 tap-highlighted, every
stack still inside its own puck. 109 tests passing.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
2026-09-01 04:24:36 -06:00
..

Hold'em dealer tests

Unit tests for the money logic behind /Casino/TexasHoldem — the betting engine, the side-pot calculator, the split calculator and the table state.

node --test tests/holdem/*.test.js

No install step, no package.json, no dependencies. The browser modules are plain script-tag files that each end with a module.exports guard, so Node can require them as-is; load.js puts them on globalThis under the same names they use to find each other in the page, in the load order from TexasHoldem.cshtml.

What's covered

File Covers
potCalculator.test.js Main and side pots, dead money, uncalled bets, odd-cent distribution
betting.test.js Blinds, street completion, raises reopening the action, all-in run-outs
state.test.js Button rotation, which seats post blinds, session standings
splitCalculator.test.js Chopped pots, odd chips, unmakeable denominations
invariants.test.js 1000 randomised hands per property (see below)

Why the randomised suite exists

Every correctness bug found in this tool so far has been shape-dependent: blinds posted to empty chairs, the button skipping past players, heads-up acting out of order, an overbet announced as a side pot. None of them show up on a full six-handed table with equal stacks, which is the table anyone writes a fixed example for.

invariants.test.js deals a thousand hands across random seat counts, random empty chairs, random stack depths and random dealer input, and checks the things a dealer would notice being wrong:

  • chips are never created or destroyed during play
  • the pot breakdown plus the uncalled returns always equal the money that went in
  • paying the pot out settles it to the cent
  • once uncalled chips are handed back, nobody is still betting above the whole table
  • the button and both blinds always land on players who are actually in the hand

The generator is seeded, so a failure reproduces from the seed printed in the message rather than being a flake to re-run.