import { describe, expect, it } from "vitest"; import type { StorageAdapter } from "./saveRepository"; import { AccountRepository } from "./accountRepository"; function memoryStorage(): StorageAdapter { const data = new Map(); return { getItem: (key) => data.get(key) ?? null, setItem: (key, value) => { data.set(key, value); }, }; } const testHasher = async (password: string, salt: string) => { const checksum = [...password].reduce((total, character) => total + character.charCodeAt(0), 0); return `derived:${salt}:${checksum}`; }; describe("AccountRepository", () => { it("requires both a username and password", async () => { const repository = new AccountRepository(memoryStorage(), testHasher, () => "salt"); await expect(repository.create("", "secret")).resolves.toEqual({ ok: false, reason: "missing-credentials" }); await expect(repository.create("healer", "")).resolves.toEqual({ ok: false, reason: "missing-credentials" }); await expect(repository.authenticate("healer", "")).resolves.toEqual({ ok: false, reason: "missing-credentials" }); }); it("requires account creation before sign-in", async () => { const repository = new AccountRepository(memoryStorage(), testHasher, () => "salt"); await expect(repository.authenticate("new-healer", "secret")).resolves.toEqual({ ok: false, reason: "account-not-found" }); await expect(repository.create("new-healer", "secret")).resolves.toEqual({ ok: true, username: "new-healer" }); await expect(repository.authenticate("new-healer", "secret")).resolves.toEqual({ ok: true, username: "new-healer" }); }); it("rejects an incorrect password and duplicate account names", async () => { const repository = new AccountRepository(memoryStorage(), testHasher, () => "salt"); await repository.create("Wayfinder", "correct"); await expect(repository.authenticate("wayfinder", "wrong")).resolves.toEqual({ ok: false, reason: "invalid-password" }); await expect(repository.create(" wayfinder ", "another")).resolves.toEqual({ ok: false, reason: "account-exists" }); }); it("persists only a derived password verifier", async () => { const storage = memoryStorage(); const repository = new AccountRepository(storage, testHasher, () => "unique-salt"); await repository.create("healer", "plaintext-secret"); const persisted = storage.getItem("i-want-to-heal:accounts:v1") ?? ""; expect(persisted).toContain("derived:unique-salt:"); expect(persisted).not.toContain("plaintext-secret"); expect(JSON.parse(persisted).healer).not.toHaveProperty("password"); }); });