import assert from "node:assert/strict"; import { describe, it } from "node:test"; import type { ActionRegistryItem } from "@/types/appops"; import { buildActionRegistryPresetView, buildActionRegistryView, getActionRegistryPresetFilters, paginateActionRegistryItems, type ActionRegistryFilters } from "./actionRegistryView.ts"; const item = (overrides: Partial): ActionRegistryItem => ({ id: "safety.summary", label: "Safety / Summary", category: "safety", target: "safety", risk: "low", capability: "read_only", policyDecision: "allowed", policyReason: "Read-only summary.", ...overrides, }); const registryItems: ActionRegistryItem[] = [ item({ id: "safety.summary", label: "Safety / Summary", category: "safety", target: "safety", risk: "low", capability: "read_only", policyDecision: "allowed" }), item({ id: "volume.delete", label: "Volume / Delete", category: "volume", target: "volume", risk: "critical", capability: "destructive", policyDecision: "blocked" }), item({ id: "stack.redeploy", label: "Stack / Redeploy", category: "stack", target: "stack", risk: "high", capability: "operator", policyDecision: "approval_required" }), item({ id: "radarr.add_movie", label: "Radarr / Add Movie", category: "radarr", target: "radarr", risk: "low", capability: "operator", policyDecision: "allowed" }), ]; describe("buildActionRegistryView", () => { it("filters by search, category, risk and policy", () => { const filters: ActionRegistryFilters = { query: "delete", category: "volume", risk: "critical", policyDecision: "blocked", capability: "destructive", }; const result = buildActionRegistryView(registryItems, filters); assert.deepEqual(result.items.map((entry) => entry.id), ["volume.delete"]); assert.equal(result.activeFilterCount, 5); }); it("computes facets from the full item set before filtering", () => { const result = buildActionRegistryView(registryItems, { query: "radarr" }); assert.deepEqual(result.items.map((entry) => entry.id), ["radarr.add_movie"]); assert.deepEqual(result.facets.categories, ["radarr", "safety", "stack", "volume"]); assert.equal(result.facets.policy.blocked, 1); assert.equal(result.facets.risk.critical, 1); assert.equal(result.facets.capability.read_only, 1); }); it("sorts highest-risk blocked actions first by default", () => { const result = buildActionRegistryView(registryItems, {}); assert.deepEqual(result.items.map((entry) => entry.id), [ "volume.delete", "stack.redeploy", "radarr.add_movie", "safety.summary", ]); }); it("provides operator preset filters for common review modes", () => { assert.deepEqual(getActionRegistryPresetFilters("blocked_destructive"), { policyDecision: "blocked", capability: "destructive", }); assert.deepEqual(getActionRegistryPresetFilters("approval_needed"), { policyDecision: "approval_required", }); assert.deepEqual(getActionRegistryPresetFilters("safe_read_only"), { policyDecision: "allowed", capability: "read_only", }); }); it("describes active presets with count and operator intent", () => { const blocked = buildActionRegistryPresetView("blocked_destructive", registryItems); const approval = buildActionRegistryPresetView("approval_needed", registryItems); assert.equal(blocked.label, "Blocked destructive"); assert.equal(blocked.count, 1); assert.equal(blocked.filters.policyDecision, "blocked"); assert.match(blocked.description, /gevaarlijke/i); assert.equal(approval.count, 1); assert.match(approval.description, /approval/i); }); it("bounds registry rendering and clamps pages after filtering", () => { const items = Array.from({ length: 65 }, (_, index) => item({ id: `action.${index}` })); const secondPage = paginateActionRegistryItems(items, 2, 30); assert.equal(secondPage.items.length, 30); assert.equal(secondPage.start, 31); assert.equal(secondPage.end, 60); assert.equal(secondPage.pageCount, 3); const clamped = paginateActionRegistryItems(items.slice(0, 4), 9, 30); assert.equal(clamped.page, 1); assert.equal(clamped.items.length, 4); assert.equal(clamped.start, 1); assert.equal(clamped.end, 4); }); });