import { describe, expect, it } from "vitest"; import { validateTicketCode } from "./entry-flow.js"; // validateTicketCode is the manual-entry typo guard: an all-digit code whose last digit // is the Luhn check of the rest. The booth uses it to reject a mistyped ticket up front // (instead of a confusing "session not found"). The capacity-gate / print-hold / sign- // before-open paths of EntryFlow need device fakes and are exercised in the device + // route phases; here we pin the pure, exported checksum contract. describe("validateTicketCode (Luhn)", () => { it("accepts a well-formed 11-digit id", () => { // 10-digit body + its Luhn check digit. 0000000000 → check digit 0. expect(validateTicketCode("00000000000")).toBe(true); }); it("rejects a single-digit typo", () => { expect(validateTicketCode("00000000000")).toBe(true); expect(validateTicketCode("00000000010")).toBe(false); // flipped a digit, checksum now wrong }); it("rejects non-digit and out-of-length strings", () => { expect(validateTicketCode("abc")).toBe(false); expect(validateTicketCode("123")).toBe(false); // too short expect(validateTicketCode("123456789012345")).toBe(false); // too long expect(validateTicketCode("")).toBe(false); }); it("round-trips a generated body+check (Luhn is self-consistent)", () => { // Construct a valid code: pick a body, compute its check the same way the issuer does. const body = "4992739871"; // brute the check digit 0..9 — exactly one makes a valid code. const valid = Array.from({ length: 10 }, (_, d) => body + d).filter(validateTicketCode); expect(valid).toHaveLength(1); }); it("accepts a legacy 13-digit id shape", () => { // 12-digit body 000000000000 → check 0; the validator is length-agnostic in 10..14. expect(validateTicketCode("0000000000000")).toBe(true); }); });