import { describe, it, expect, vi } from "vitest"; vi.mock("server-only", () => ({})); vi.mock("@/lib/prisma", () => ({ prisma: {} })); const { hashToken, isInviteValid } = await import("@/lib/ce-invites"); describe("hashToken", () => { it("est déterministe — même input → même hash", () => { expect(hashToken("abc")).toBe(hashToken("abc")); }); it("hash sha256 (64 hex chars)", () => { expect(hashToken("token")).toMatch(/^[0-9a-f]{64}$/); }); it("inputs différents → hashes différents", () => { expect(hashToken("abc")).not.toBe(hashToken("abd")); }); it("ne retourne pas le plain (jamais persisté)", () => { expect(hashToken("secret-plain-text")).not.toContain("secret"); }); }); describe("isInviteValid", () => { const future = new Date(Date.now() + 24 * 3600 * 1000); const past = new Date(Date.now() - 24 * 3600 * 1000); it("vrai si non consommé et non expiré", () => { expect(isInviteValid({ expiresAt: future, usedAt: null })).toBe(true); }); it("faux si déjà consommé", () => { expect(isInviteValid({ expiresAt: future, usedAt: new Date() })).toBe(false); }); it("faux si expiré", () => { expect(isInviteValid({ expiresAt: past, usedAt: null })).toBe(false); }); it("faux si consommé ET expiré (les 2 raisons)", () => { expect(isInviteValid({ expiresAt: past, usedAt: new Date() })).toBe(false); }); it("accepte un `now` injecté pour tests temporels", () => { const ref = new Date("2026-06-01"); const justAfter = new Date("2026-06-02"); expect(isInviteValid({ expiresAt: justAfter, usedAt: null }, ref)).toBe(true); expect(isInviteValid({ expiresAt: ref, usedAt: null }, justAfter)).toBe(false); }); });