import { beforeEach, describe, expect, it, vi } from "vitest"; import { PERMS } from "@/lib/permission-slugs"; import type { HousekeepingCapabilityContext } from "../../../foundation/contracts"; const { audit, disconnectUser, insertValues, selectLimit } = vi.hoisted(() => ({ audit: vi.fn(), disconnectUser: vi.fn(), insertValues: vi.fn(), selectLimit: vi.fn(), })); vi.mock("@/lib/auth", () => ({ invalidateLoginCache: vi.fn() })); vi.mock("@/lib/auth/password", () => ({ hashPassword: vi.fn() })); vi.mock("@/lib/db", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, db: { ...actual.db, select: vi.fn(() => ({ from: vi.fn(() => ({ where: vi.fn(() => ({ limit: selectLimit })), })), })), insert: vi.fn(() => ({ values: insertValues })), }, }; }); vi.mock("@/lib/services/audit", async (importOriginal) => ({ ...(await importOriginal()), logAudit: audit, })); vi.mock("@/lib/services/rcon", async (importOriginal) => ({ ...(await importOriginal()), rcon: { disconnectUser }, })); vi.mock("@/lib/services/webhook", () => ({ notify: vi.fn() })); import { peopleMutationService } from "./mutations"; function capabilityContext( granted: readonly string[], ): HousekeepingCapabilityContext { const permissions = new Set(granted); return { actor: { id: 42, username: "operator", rank: 6 }, isSuperAdmin: false, has: (slug) => permissions.has(slug), hasAny: (...slugs) => slugs.some((slug) => permissions.has(slug)), hasAll: (...slugs) => slugs.every((slug) => permissions.has(slug)), }; } beforeEach(() => { vi.clearAllMocks(); selectLimit.mockResolvedValue([ { id: 7, username: "Alice", mail: "alice@example.test", rank: 2, motto: "Ready", credits: 100, pixels: 50, online: "1", }, ]); insertValues.mockResolvedValue([{}]); disconnectUser.mockResolvedValue(true); audit.mockResolvedValue(undefined); }); describe("People production reason audit", () => { it("persists the nonblank sanction reason with before and after evidence", async () => { const result = await peopleMutationService.execute( { capability: capabilityContext([PERMS.USERS_BAN]), correlationId: "production-ban", }, "user.ban", { userId: 7, reason: "Repeated harassment", duration: 24, type: "account", }, ); expect(result).toMatchObject({ ok: true }); expect(audit).toHaveBeenCalledWith( expect.objectContaining({ action: "people.user.ban", before: expect.objectContaining({ id: 7, banned: false }), after: expect.objectContaining({ id: 7, banned: true, reason: "Repeated harassment", }), }), ); expect(audit.mock.calls[0]?.[0]?.before).not.toHaveProperty("mail"); expect(audit.mock.calls[0]?.[0]?.after).not.toHaveProperty("mail"); }); });