Files
EpicNext-Cms/src/features/housekeeping/domains/people/services/mutations-reason-production.test.ts
T

105 lines
2.9 KiB
TypeScript

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<typeof import("@/lib/db")>();
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<typeof import("@/lib/services/audit")>()),
logAudit: audit,
}));
vi.mock("@/lib/services/rcon", async (importOriginal) => ({
...(await importOriginal<typeof import("@/lib/services/rcon")>()),
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: "[email protected]",
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");
});
});