120 lines
3.6 KiB
TypeScript
120 lines
3.6 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { z } from "zod";
|
|
import { PERMS } from "@/lib/permission-slugs";
|
|
import type { HousekeepingCommand } from "../commands/registry";
|
|
import type {
|
|
HousekeepingCapabilityContext,
|
|
HousekeepingDomainManifest,
|
|
} from "../contracts";
|
|
import type { HousekeepingRegistry } from "../registry";
|
|
import { searchNavigationAndCommands } from "./navigation-search";
|
|
|
|
function context(granted: readonly string[]): HousekeepingCapabilityContext {
|
|
const permissions = new Set(granted);
|
|
return {
|
|
actor: { id: 42, username: "operator", rank: 7 },
|
|
isSuperAdmin: false,
|
|
has: (slug) => permissions.has(slug),
|
|
hasAny: (...slugs) => slugs.some((slug) => permissions.has(slug)),
|
|
hasAll: (...slugs) => slugs.every((slug) => permissions.has(slug)),
|
|
};
|
|
}
|
|
|
|
const peopleManifest = {
|
|
id: "people",
|
|
labelKey: "pages.housekeeping.domains.people.title",
|
|
descriptionKey: "pages.housekeeping.domains.people.description",
|
|
iconId: "users",
|
|
canonicalHref: "/ase/people",
|
|
capability: { mode: "any", slugs: [PERMS.USERS_VIEW] },
|
|
routes: [
|
|
{
|
|
id: "people.users",
|
|
href: "/ase/people/users",
|
|
labelKey: "pages.housekeeping.routes.people.users",
|
|
capability: { mode: "any", slugs: [PERMS.USERS_VIEW] },
|
|
},
|
|
{
|
|
id: "people.moderation",
|
|
href: "/ase/people/moderation",
|
|
labelKey: "pages.housekeeping.routes.people.moderation",
|
|
capability: { mode: "any", slugs: [PERMS.MODERATION_VIEW] },
|
|
},
|
|
],
|
|
searchProviders: [],
|
|
inboxSources: [],
|
|
widgets: [],
|
|
} as const satisfies HousekeepingDomainManifest;
|
|
|
|
const registry: HousekeepingRegistry = { domains: [peopleManifest] };
|
|
|
|
function command(
|
|
id: string,
|
|
permission: string,
|
|
): HousekeepingCommand<Record<string, never>, never> {
|
|
return {
|
|
id,
|
|
owner: "people",
|
|
risk: "safe",
|
|
capability: { mode: "any", slugs: [permission] },
|
|
input: z.object({}),
|
|
requiresReason: false,
|
|
rateLimit: { attempts: 3, windowMs: 60_000 },
|
|
execute: async () => ({
|
|
ok: true,
|
|
data: undefined as never,
|
|
correlationId: "command",
|
|
}),
|
|
};
|
|
}
|
|
|
|
const translations: Record<string, string> = {
|
|
"pages.housekeeping.domains.people.title": "People",
|
|
"pages.housekeeping.domains.people.description": "Accounts and moderation",
|
|
"pages.housekeeping.routes.people.users": "User accounts",
|
|
"pages.housekeeping.routes.people.moderation": "Moderation queue",
|
|
};
|
|
|
|
describe("navigation and command search", () => {
|
|
it("matches permitted domain/routes/commands and omits forbidden entries", () => {
|
|
const result = searchNavigationAndCommands({
|
|
registry,
|
|
commands: [
|
|
command("people.user.refresh", PERMS.USERS_VIEW),
|
|
command("people.moderation.ban", PERMS.MODERATION_VIEW),
|
|
],
|
|
context: context([PERMS.USERS_VIEW]),
|
|
term: "user",
|
|
translate: (key) => translations[key] ?? key,
|
|
});
|
|
|
|
expect(result.navigation.map((hit) => hit.id)).toEqual([
|
|
"route:people.users",
|
|
]);
|
|
expect(result.commands.map((hit) => hit.commandId)).toEqual([
|
|
"people.user.refresh",
|
|
]);
|
|
expect(result.navigation[0]?.href).toBe("/ase/people/users");
|
|
expect(result.commands[0]?.href).toBe("/ase/people");
|
|
});
|
|
|
|
it("normalizes terms and keeps registry/command order stable", () => {
|
|
const result = searchNavigationAndCommands({
|
|
registry,
|
|
commands: [
|
|
command("people.user.refresh", PERMS.USERS_VIEW),
|
|
command("people.user.inspect", PERMS.USERS_VIEW),
|
|
],
|
|
context: context([PERMS.USERS_VIEW]),
|
|
term: " PEOPLE ",
|
|
translate: (key) => translations[key] ?? key,
|
|
});
|
|
|
|
expect(result.navigation.map((hit) => hit.id)).toEqual(["domain:people"]);
|
|
expect(result.commands.map((hit) => hit.commandId)).toEqual([
|
|
"people.user.refresh",
|
|
"people.user.inspect",
|
|
]);
|
|
});
|
|
});
|