import { describe, it, expect, beforeEach, afterEach } from "vitest"; import { pseudonymize } from "./pseudonymize"; describe("pseudonymize", () => { const originalSalt = process.env["AUDIT_PSEUDONYM_SALT"]; beforeEach(() => { process.env["AUDIT_PSEUDONYM_SALT"] = "test-salt-1"; }); afterEach(() => { if (originalSalt === undefined) { delete process.env["AUDIT_PSEUDONYM_SALT"]; } else { process.env["AUDIT_PSEUDONYM_SALT"] = originalSalt; } }); it("returns a string prefixed with 'erased-'", () => { const result = pseudonymize("user_42"); expect(result).toMatch(/^erased-/); }); it("produces exactly 16 hex chars after the prefix", () => { const result = pseudonymize("user_42"); const hex = result.slice("erased-".length); expect(hex).toHaveLength(16); expect(hex).toMatch(/^[0-9a-f]+$/); }); it("is deterministic — same salt + actorId always yields the same token", () => { const a = pseudonymize("user_42"); const b = pseudonymize("user_42"); expect(a).toBe(b); }); it("differs when actorId differs (same salt)", () => { const a = pseudonymize("user_42"); const b = pseudonymize("user_99"); expect(a).not.toBe(b); }); it("differs when the salt changes", () => { const withSalt1 = pseudonymize("user_42"); process.env["AUDIT_PSEUDONYM_SALT"] = "test-salt-2"; const withSalt2 = pseudonymize("user_42"); expect(withSalt1).not.toBe(withSalt2); }); it("uses the fallback salt when env var is absent", () => { delete process.env["AUDIT_PSEUDONYM_SALT"]; // Should not throw; just use the fallback. const result = pseudonymize("user_1"); expect(result).toMatch(/^erased-[0-9a-f]{16}$/); }); });