import { describe, expect, it, vi } from "vitest"; import { AccountRepository } from "./accountRepository"; import { OnlineApiError, type OnlineRepository } from "./onlineRepository"; function onlineStub(overrides: Partial = {}): OnlineRepository { return { register: vi.fn(async (username: string) => ({ id: 1, username })), login: vi.fn(async (username: string) => ({ id: 1, username })), session: vi.fn(async () => null), logout: vi.fn(async () => undefined), ...overrides, } as unknown as OnlineRepository; } describe("AccountRepository", () => { it("requires both username and password before contacting server", async () => { const online = onlineStub(); const repository = new AccountRepository(online); await expect(repository.create("", "secret")).resolves.toEqual({ ok: false, reason: "missing-credentials" }); await expect(repository.authenticate("healer", "")).resolves.toEqual({ ok: false, reason: "missing-credentials" }); expect(online.register).not.toHaveBeenCalled(); }); it("creates and authenticates real server accounts", async () => { const repository = new AccountRepository(onlineStub()); await expect(repository.create("Wayfinder", "long-password")).resolves.toEqual({ ok: true, username: "Wayfinder" }); await expect(repository.authenticate("Wayfinder", "long-password")).resolves.toEqual({ ok: true, username: "Wayfinder" }); }); it("maps server conflicts, invalid credentials, and outages", async () => { const conflict = new AccountRepository(onlineStub({ register: vi.fn(async () => { throw new OnlineApiError("exists", 409); }) })); await expect(conflict.create("Wayfinder", "long-password")).resolves.toMatchObject({ ok: false, reason: "account-exists" }); const invalid = new AccountRepository(onlineStub({ login: vi.fn(async () => { throw new OnlineApiError("bad login", 401); }) })); await expect(invalid.authenticate("Wayfinder", "wrong-password")).resolves.toMatchObject({ ok: false, reason: "invalid-password" }); const outage = new AccountRepository(onlineStub({ login: vi.fn(async () => { throw new OnlineApiError("offline", 0); }) })); await expect(outage.authenticate("Wayfinder", "long-password")).resolves.toMatchObject({ ok: false, reason: "server-unavailable" }); }); });