import { describe, expect, it } from "vitest"; import { evaluateCodeAttempt, generateCode, hashCode, } from "./verificationCode"; const FUTURE = new Date("2030-01-01T00:00:00Z"); const NOW = new Date("2026-05-27T12:00:00Z"); const CORRECT_HASH = "correct-hash"; const WRONG_HASH = "wrong-hash"; describe("generateCode", () => { it("returns a 6-digit numeric string", () => { const code = generateCode(); expect(code).toMatch(/^\d{6}$/); }); }); describe("hashCode", () => { it("produces the same hash for the same code+secret", () => { const a = hashCode("482911", "secret-x"); const b = hashCode("482911", "secret-x"); expect(a).toBe(b); }); it("produces different hashes when the secret differs", () => { const a = hashCode("482911", "secret-x"); const b = hashCode("482911", "secret-y"); expect(a).not.toBe(b); }); }); describe("evaluateCodeAttempt", () => { it("rejects a wrong code and increments attempts", () => { const result = evaluateCodeAttempt({ submittedCodeHash: WRONG_HASH, row: { codeHash: CORRECT_HASH, attempts: 0, expires: FUTURE }, now: NOW, }); expect(result).toEqual({ outcome: "wrong", newAttempts: 1 }); }); it("accepts a correct code", () => { const result = evaluateCodeAttempt({ submittedCodeHash: CORRECT_HASH, row: { codeHash: CORRECT_HASH, attempts: 0, expires: FUTURE }, now: NOW, }); expect(result).toEqual({ outcome: "ok" }); }); it("locks out on the 5th consecutive wrong attempt", () => { const result = evaluateCodeAttempt({ submittedCodeHash: WRONG_HASH, row: { codeHash: CORRECT_HASH, attempts: 4, expires: FUTURE }, now: NOW, }); expect(result).toEqual({ outcome: "locked-out" }); }); it("still rejects a correct code submitted after lock-out", () => { const result = evaluateCodeAttempt({ submittedCodeHash: CORRECT_HASH, row: { codeHash: CORRECT_HASH, attempts: 5, expires: FUTURE }, now: NOW, }); expect(result).toEqual({ outcome: "locked-out" }); }); it("reports no-such-row when there's no row for the email", () => { const result = evaluateCodeAttempt({ submittedCodeHash: CORRECT_HASH, row: null, now: NOW, }); expect(result).toEqual({ outcome: "no-such-row" }); }); it("reports expired when the row's expiry is in the past", () => { const expired = new Date(NOW.getTime() - 1000); const result = evaluateCodeAttempt({ submittedCodeHash: CORRECT_HASH, row: { codeHash: CORRECT_HASH, attempts: 0, expires: expired }, now: NOW, }); expect(result).toEqual({ outcome: "expired" }); }); });