97 lines
3.5 KiB
TypeScript
97 lines
3.5 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
import { z } from "zod";
|
|
|
|
vi.mock("@/lib/auth", () => ({ invalidateLoginCache: vi.fn() }));
|
|
vi.mock("@/lib/auth/password", () => ({ hashPassword: vi.fn() }));
|
|
|
|
import { housekeepingCommandRegistryReady } from "../../commands";
|
|
import { COMMUNITY_COMMAND_IDS } from "../../domains/people/commands/community-commands";
|
|
import { MODERATION_COMMAND_IDS } from "../../domains/people/commands/moderation-commands";
|
|
import { SUPPORT_COMMAND_IDS } from "../../domains/people/commands/support-commands";
|
|
import { USER_COMMAND_IDS } from "../../domains/people/commands/user-commands";
|
|
import { SYSTEM_COMMAND_IDS } from "../../domains/system/commands/system-commands";
|
|
import { anyCapability, ok } from "../contracts";
|
|
import {
|
|
defineHousekeepingCommands,
|
|
registerHousekeepingCommands,
|
|
} from "./bootstrap";
|
|
import {
|
|
getHousekeepingCommand,
|
|
type HousekeepingCommand,
|
|
registerHousekeepingCommand,
|
|
} from "./registry";
|
|
|
|
describe("housekeeping command bootstrap", () => {
|
|
it("preserves heterogeneous concrete input and output types", () => {
|
|
const stringCommand: HousekeepingCommand<
|
|
{ value: string },
|
|
{ length: number }
|
|
> = {
|
|
id: "system.bootstrap.string-shape",
|
|
owner: "system",
|
|
risk: "safe",
|
|
capability: anyCapability("admin.settings.view"),
|
|
input: z.object({ value: z.string() }),
|
|
requiresReason: false,
|
|
rateLimit: { attempts: 1, windowMs: 1_000 },
|
|
execute: async (context, input) =>
|
|
ok({ length: input.value.length }, context.correlationId),
|
|
};
|
|
const numberCommand: HousekeepingCommand<
|
|
{ count: number },
|
|
{ doubled: number }
|
|
> = {
|
|
id: "system.bootstrap.number-shape",
|
|
owner: "system",
|
|
risk: "safe",
|
|
capability: anyCapability("admin.settings.view"),
|
|
input: z.object({ count: z.number().int() }),
|
|
requiresReason: false,
|
|
rateLimit: { attempts: 2, windowMs: 2_000 },
|
|
execute: async (context, input) =>
|
|
ok({ doubled: input.count * 2 }, context.correlationId),
|
|
};
|
|
|
|
const commands = defineHousekeepingCommands(stringCommand, numberCommand);
|
|
const stringInput: z.input<(typeof commands)[0]["input"]> = {
|
|
value: "typed",
|
|
};
|
|
const numberInput: z.input<(typeof commands)[1]["input"]> = { count: 4 };
|
|
expect(commands[0].input.parse(stringInput)).toEqual({ value: "typed" });
|
|
expect(commands[1].input.parse(numberInput)).toEqual({ count: 4 });
|
|
expect(() => registerHousekeepingCommands(commands)).toThrow(
|
|
"command registry is sealed",
|
|
);
|
|
});
|
|
it("registers the complete current list and seals during module initialization", () => {
|
|
expect(housekeepingCommandRegistryReady).toBe(true);
|
|
expect(
|
|
SYSTEM_COMMAND_IDS.map((id) => getHousekeepingCommand(id)?.id),
|
|
).toEqual(SYSTEM_COMMAND_IDS);
|
|
expect(
|
|
USER_COMMAND_IDS.map((id) => getHousekeepingCommand(id)?.id),
|
|
).toEqual(USER_COMMAND_IDS);
|
|
expect(
|
|
COMMUNITY_COMMAND_IDS.map((id) => getHousekeepingCommand(id)?.id),
|
|
).toEqual(COMMUNITY_COMMAND_IDS);
|
|
expect(
|
|
SUPPORT_COMMAND_IDS.map((id) => getHousekeepingCommand(id)?.id),
|
|
).toEqual(SUPPORT_COMMAND_IDS);
|
|
expect(
|
|
MODERATION_COMMAND_IDS.map((id) => getHousekeepingCommand(id)?.id),
|
|
).toEqual(MODERATION_COMMAND_IDS);
|
|
expect(() =>
|
|
registerHousekeepingCommand({
|
|
id: "system.bootstrap.too-late",
|
|
owner: "system",
|
|
risk: "safe",
|
|
capability: anyCapability("admin.settings.view"),
|
|
input: z.object({}),
|
|
requiresReason: false,
|
|
rateLimit: { attempts: 1, windowMs: 1_000 },
|
|
execute: async (context) => ok(null, context.correlationId),
|
|
}),
|
|
).toThrow("command registry is sealed");
|
|
});
|
|
});
|