// What happens when the browser refuses to save. // // The table keeps working — that was always true and is still the right behaviour. // What was missing is anybody being told, which is the same shape of fault the bank // check exists for: silent until it's too late to act on. const test = require("node:test"); const assert = require("node:assert"); const { HoldemState, makeTable } = require("./load"); function withStorage(behaviour) { const calls = []; globalThis.localStorage = { setItem(key, value) { calls.push({ key, value }); if (behaviour === "throw") { const error = new Error("QuotaExceededError"); error.name = "QuotaExceededError"; throw error; } }, getItem: () => null, removeItem() {}, }; return calls; } test.beforeEach(() => { HoldemState.saveFailed = false; HoldemState.onSaveFailed = null; }); test.after(() => { delete globalThis.localStorage; HoldemState.saveFailed = false; HoldemState.onSaveFailed = null; }); test("a save that works says so and leaves no mark", () => { withStorage("ok"); const state = makeTable({ seatCount: 6, seated: [0, 1], stack: 100 }); assert.equal(HoldemState.save(state), true); assert.equal(HoldemState.saveFailed, false); }); test("a save that fails says so rather than throwing", () => { withStorage("throw"); const state = makeTable({ seatCount: 6, seated: [0, 1], stack: 100 }); assert.equal(HoldemState.save(state), false); assert.equal(HoldemState.saveFailed, true); }); test("the table is told once, not on every action", () => { // A dealer taps the bar thirty times a hand and doesn't need thirty warnings. withStorage("throw"); const state = makeTable({ seatCount: 6, seated: [0, 1], stack: 100 }); let told = 0; HoldemState.onSaveFailed = () => { told++; }; for (let i = 0; i < 20; i++) HoldemState.save(state); assert.equal(told, 1); }); test("the failure is handed the error, so the reason can be reported later", () => { withStorage("throw"); const state = makeTable({ seatCount: 6, seated: [0, 1], stack: 100 }); let seen = null; HoldemState.onSaveFailed = error => { seen = error; }; HoldemState.save(state); assert.equal(seen && seen.name, "QuotaExceededError"); }); test("a failing save still doesn't stop the table", () => { // The chips have already moved in memory; refusing to continue would be worse // than not persisting. withStorage("throw"); const state = makeTable({ seatCount: 6, seated: [0, 1, 2], stack: 100 }); state.seats[0].stack = 175; assert.doesNotThrow(() => HoldemState.save(state)); assert.equal(state.seats[0].stack, 175); }); test("no listener is not an error", () => { withStorage("throw"); const state = makeTable({ seatCount: 6, seated: [0, 1], stack: 100 }); HoldemState.onSaveFailed = null; assert.doesNotThrow(() => HoldemState.save(state)); assert.equal(HoldemState.saveFailed, true); });