import { describe, expect, it, vi } from "vitest"; import { getAnonymizationDirectory } from "../lib/anonymization.js"; describe("anonymization directory", () => { it("persists aliases so existing resources keep the same identity when new resources appear", async () => { let storedAliases: Record = { resource_a: { displayName: "Iron Man", eid: "iron.man", }, }; const resourcesRoundOne = [ { id: "resource_a", eid: "alice", displayName: "Alice", email: "alice@example.com", lcrCents: 14000, }, { id: "resource_b", eid: "bob", displayName: "Bob", email: "bob@example.com", lcrCents: 11000, }, ]; const resourcesRoundTwo = [ ...resourcesRoundOne, { id: "resource_c", eid: "carol", displayName: "Carol", email: "carol@example.com", lcrCents: 12500, }, ]; const db = { systemSettings: { findUnique: vi.fn(async () => ({ anonymizationEnabled: true, anonymizationDomain: "superhartmut.de", anonymizationSeed: "stable-seed", anonymizationMode: "global", anonymizationAliases: storedAliases, })), update: vi.fn(async ({ data }: { data: { anonymizationAliases: typeof storedAliases } }) => { storedAliases = data.anonymizationAliases; return {}; }), }, resource: { findMany: vi .fn() .mockResolvedValueOnce(resourcesRoundOne) .mockResolvedValueOnce(resourcesRoundTwo), }, }; const firstDirectory = await getAnonymizationDirectory(db as never); const secondDirectory = await getAnonymizationDirectory(db as never); expect(firstDirectory?.byResourceId.get("resource_a")).toMatchObject({ displayName: "Iron Man", eid: "iron.man", email: "iron.man@superhartmut.de", }); expect(firstDirectory?.byResourceId.get("resource_b")).toBeDefined(); expect(secondDirectory?.byResourceId.get("resource_a")).toMatchObject({ displayName: "Iron Man", eid: "iron.man", email: "iron.man@superhartmut.de", }); expect(secondDirectory?.byResourceId.get("resource_b")).toEqual( firstDirectory?.byResourceId.get("resource_b"), ); expect(secondDirectory?.byResourceId.get("resource_c")).toBeDefined(); expect(db.systemSettings.update).toHaveBeenCalledTimes(2); }); it("regenerates legacy aliases with digits into stable aliases without numeric characters", async () => { let storedAliases: Record = { resource_a: { displayName: "Baloo 16", eid: "baloo.16", }, }; const db = { systemSettings: { findUnique: vi.fn(async () => ({ anonymizationEnabled: true, anonymizationDomain: "superhartmut.de", anonymizationSeed: "stable-seed", anonymizationMode: "global", anonymizationAliases: storedAliases, })), update: vi.fn(async ({ data }: { data: { anonymizationAliases: typeof storedAliases } }) => { storedAliases = data.anonymizationAliases; return {}; }), }, resource: { findMany: vi.fn().mockResolvedValue([ { id: "resource_a", eid: "alice", displayName: "Alice", email: "alice@example.com", lcrCents: 6000, }, ]), }, }; const directory = await getAnonymizationDirectory(db as never); const alias = directory?.byResourceId.get("resource_a"); expect(alias).toBeDefined(); expect(alias?.displayName).not.toContain("16"); expect(alias?.eid).not.toContain("16"); expect(alias?.displayName).toMatch(/^[A-Za-z]+(?: [A-Za-z]+)*$/); expect(alias?.eid).toMatch(/^[a-z]+(?:\.[a-z]+)*$/); expect(db.systemSettings.update).toHaveBeenCalledTimes(1); }); });