// Chips only ever leave this tool because a dealer meant them to. Starting the next // hand clears every seat's contribution, so an unresolved pot is simply destroyed — // the UI now asks first, and the number it quotes has to be exactly what goes. const { test, describe } = require("node:test"); const assert = require("node:assert/strict"); const { Betting, HoldemState, Money, makeTable, chipsOnTable } = require("./load"); // The same measure the confirmation uses. const unresolvedPot = state => HoldemState.unresolvedContributions(state); describe("what starting the next hand destroys", () => { test("the quoted amount is exactly what leaves the table", () => { const state = makeTable({ seatCount: 6, seated: [0, 1, 2, 3], dealerSeatIndex: 0 }); Betting.beginHand(state); Betting.call(state, 3); Betting.call(state, 0); Betting.call(state, 1); Betting.check(state, 2); Betting.sweepToHandTotals(state); const before = chipsOnTable(state); const quoted = unresolvedPot(state); assert.ok(quoted > 0, "there is a pot to warn about"); HoldemState.startNextHand(state); assert.equal( Money.toCents(chipsOnTable(state)), Money.toCents(before - quoted), "the dealer must be told the real number, not an approximation" ); }); test("chips still in front of players on the current street are counted too", () => { const state = makeTable({ seatCount: 4, seated: [0, 1, 2], dealerSeatIndex: 0 }); Betting.beginHand(state); // blinds are `committed`, not yet banked Betting.raiseTo(state, 0, 25); // and so is a raise mid-street const before = chipsOnTable(state); const quoted = unresolvedPot(state); HoldemState.startNextHand(state); assert.equal(Money.toCents(chipsOnTable(state)), Money.toCents(before - quoted)); assert.ok(quoted >= 25, `a live raise has to be included; quoted ${quoted}`); }); test("a hand that was paid out properly leaves nothing to warn about", () => { const state = makeTable({ seatCount: 4, seated: [0, 1, 2], dealerSeatIndex: 0 }); Betting.beginHand(state); Betting.call(state, 0); Betting.call(state, 1); Betting.check(state, 2); Betting.sweepToHandTotals(state); const pot = HoldemState.totalPot(state); const payouts = [{ id: state.seats[0].id, label: "Ann", amount: pot }]; HoldemState.recordHand(state, payouts); Betting.creditWinnings(state, payouts); HoldemState.startNextHand(state); assert.equal(unresolvedPot(state), 0, "nothing left over after a settled hand"); }); test("settling then dealing on conserves every chip", () => { const state = makeTable({ seatCount: 6, seated: [0, 1, 2, 3], dealerSeatIndex: 0 }); const start = chipsOnTable(state); for (let hand = 0; hand < 5; hand++) { Betting.beginHand(state); const live = Betting.liveSeats(state); live.forEach(s => { if (Betting.toCall(state, s.player) > 0) Betting.call(state, s.index); }); Betting.sweepToHandTotals(state); const pot = HoldemState.totalPot(state); const winner = Betting.liveSeats(state)[0]; const payouts = [{ id: winner.player.id, label: "w", amount: pot }]; HoldemState.recordHand(state, payouts); Betting.creditWinnings(state, payouts); HoldemState.startNextHand(state); assert.equal(chipsOnTable(state), start, `chips drifted on hand ${hand + 1}`); } }); test("an empty table has no phantom pot to warn about", () => { const state = makeTable({ seatCount: 6, seated: [] }); assert.equal(unresolvedPot(state), 0); }); test("a standing ante is never warned about, because it isn't lost", () => { // The table default is a stand-in for "everyone puts the same in every hand", // used by a dealer not tracking stacks at all. It re-applies to the next hand // rather than going anywhere, so counting it would nag this dealer before // every single hand — which is why the warning measures the fields // startNextHand actually clears rather than the pot badge. const state = makeTable({ seatCount: 9, seated: [0, 1] }); state.basePotAmount = 25; state.seats.forEach(p => { p.amountOverride = null; }); // The base pot carries into the next hand, so nothing is being thrown away // and the dealer must not be asked to confirm anything. assert.equal(HoldemState.totalPot(state), 50, "the badge still shows a pot"); assert.equal(unresolvedPot(state), 0, "but none of it is at risk, so no warning"); HoldemState.startNextHand(state); assert.equal(HoldemState.totalPot(state), 50, "the standing ante applies to the new hand too"); }); });