157 lines
4.8 KiB
TypeScript
157 lines
4.8 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
import { PERMS } from "@/lib/permission-slugs";
|
|
import type { HousekeepingCapabilityContext } from "../../../foundation/contracts";
|
|
import { createEconomyCommands, ECONOMY_COMMAND_IDS } from "./economy-commands";
|
|
|
|
const expected = [
|
|
["economy.catalog.page.change", "catalog-page.change", PERMS.CATALOG_EDIT],
|
|
["economy.catalog.page.reorder", "catalog-page.reorder", PERMS.CATALOG_EDIT],
|
|
[
|
|
"economy.catalog.page.delete-tree",
|
|
"catalog-page.delete-tree",
|
|
PERMS.CATALOG_EDIT,
|
|
],
|
|
["economy.catalog.bc-page.change", "bc-page.change", PERMS.CATALOG_EDIT],
|
|
["economy.catalog.bc-page.reorder", "bc-page.reorder", PERMS.CATALOG_EDIT],
|
|
[
|
|
"economy.catalog.bc-page.delete-tree",
|
|
"bc-page.delete-tree",
|
|
PERMS.CATALOG_EDIT,
|
|
],
|
|
["economy.catalog.bc-item.change", "bc-item.change", PERMS.CATALOG_EDIT],
|
|
["economy.catalog.item.change", "catalog-item.change", PERMS.CATALOG_EDIT],
|
|
[
|
|
"economy.catalog.item.bulk-create",
|
|
"catalog-item.bulk-create",
|
|
PERMS.CATALOG_EDIT,
|
|
],
|
|
["economy.catalog.item.move", "catalog-item.move", PERMS.CATALOG_EDIT],
|
|
["economy.catalog.item.reorder", "catalog-item.reorder", PERMS.CATALOG_EDIT],
|
|
[
|
|
"economy.catalog.item.translate",
|
|
"catalog-item.translate",
|
|
PERMS.CATALOG_EDIT,
|
|
],
|
|
[
|
|
"economy.catalog.maintenance.fix-offers",
|
|
"maintenance.fix-offers",
|
|
PERMS.CATALOG_EDIT,
|
|
],
|
|
[
|
|
"economy.catalog.maintenance.fix-everything",
|
|
"maintenance.fix-everything",
|
|
PERMS.CATALOG_EDIT,
|
|
],
|
|
[
|
|
"economy.catalog.maintenance.fix-sprite-ids",
|
|
"maintenance.fix-sprite-ids",
|
|
PERMS.CATALOG_EDIT,
|
|
],
|
|
[
|
|
"economy.catalog.maintenance.reconcile-ids",
|
|
"maintenance.reconcile-ids",
|
|
PERMS.CATALOG_EDIT,
|
|
],
|
|
[
|
|
"economy.catalog.maintenance.align-ids",
|
|
"maintenance.align-ids",
|
|
PERMS.CATALOG_EDIT,
|
|
],
|
|
[
|
|
"economy.catalog.maintenance.remove-duplicates",
|
|
"maintenance.remove-duplicates",
|
|
PERMS.CATALOG_EDIT,
|
|
],
|
|
["economy.items.base.update", "items-base.update", PERMS.CATALOG_EDIT],
|
|
[
|
|
"economy.commerce.shop-article.change",
|
|
"shop-article.change",
|
|
PERMS.SHOP_EDIT,
|
|
],
|
|
[
|
|
"economy.commerce.marketplace.cancel",
|
|
"marketplace.cancel",
|
|
PERMS.SHOP_EDIT,
|
|
],
|
|
["economy.commerce.voucher.change", "voucher.change", PERMS.SHOP_EDIT],
|
|
["economy.value.category.change", "rare-category.change", PERMS.SHOP_EDIT],
|
|
["economy.value.rare.change", "rare-value.change", PERMS.SHOP_EDIT],
|
|
["economy.rewards.badge.give", "badge.give", PERMS.CATALOG_EDIT],
|
|
["economy.rewards.badge.upload", "badge.upload", PERMS.CATALOG_EDIT],
|
|
[
|
|
"economy.rewards.soundtrack.change",
|
|
"soundtrack.change",
|
|
PERMS.CATALOG_EDIT,
|
|
],
|
|
] as const;
|
|
|
|
function context(): HousekeepingCapabilityContext {
|
|
return {
|
|
actor: { id: 42, username: "operator", rank: 7 },
|
|
isSuperAdmin: false,
|
|
has: () => true,
|
|
hasAny: () => true,
|
|
hasAll: () => true,
|
|
};
|
|
}
|
|
|
|
describe("Economy commands", () => {
|
|
it("registers the exact 27-operation matrix with existing ACLs", () => {
|
|
const commands = createEconomyCommands({ execute: vi.fn() } as never);
|
|
expect(ECONOMY_COMMAND_IDS).toEqual(expected.map(([id]) => id));
|
|
expect(
|
|
commands.map((command) => [
|
|
command.id,
|
|
command.operation,
|
|
command.capability.slugs[0],
|
|
]),
|
|
).toEqual(expected);
|
|
expect(commands.every((command) => command.owner === "economy")).toBe(true);
|
|
expect(commands.every((command) => command.risk === "sensitive")).toBe(
|
|
true,
|
|
);
|
|
});
|
|
|
|
it("requires a reason for destructive, maintenance, cancellation, and grant operations", () => {
|
|
const commands = createEconomyCommands({ execute: vi.fn() } as never);
|
|
const required = commands
|
|
.filter((command) => command.requiresReason)
|
|
.map((command) => command.id);
|
|
expect(required).toEqual([
|
|
"economy.catalog.page.delete-tree",
|
|
"economy.catalog.bc-page.delete-tree",
|
|
"economy.catalog.maintenance.fix-offers",
|
|
"economy.catalog.maintenance.fix-everything",
|
|
"economy.catalog.maintenance.fix-sprite-ids",
|
|
"economy.catalog.maintenance.reconcile-ids",
|
|
"economy.catalog.maintenance.align-ids",
|
|
"economy.catalog.maintenance.remove-duplicates",
|
|
"economy.commerce.marketplace.cancel",
|
|
"economy.rewards.badge.give",
|
|
"economy.rewards.badge.upload",
|
|
]);
|
|
});
|
|
|
|
it("binds real execution to the server-authorized actor", async () => {
|
|
const execute = vi.fn(async () => ({
|
|
ok: true as const,
|
|
data: { before: null, after: { id: "1" } },
|
|
correlationId: "economy-command",
|
|
}));
|
|
const [command] = createEconomyCommands({ execute } as never);
|
|
await command.execute(
|
|
{
|
|
capability: context(),
|
|
correlationId: "economy-command",
|
|
ipAddress: "127.0.0.1",
|
|
},
|
|
{ action: "update", id: "1", caption: "Seasonal" },
|
|
);
|
|
expect(execute).toHaveBeenCalledWith(
|
|
{ correlationId: "economy-command", expectedActorId: 42 },
|
|
"catalog-page.change",
|
|
{ action: "update", id: "1", caption: "Seasonal" },
|
|
);
|
|
});
|
|
});
|