Files
govoplan-core/webui/tests/module-capabilities.test.ts

99 lines
4.5 KiB
TypeScript

import type {
OrganizationFunctionActionContext,
OrganizationFunctionActionContribution,
PlatformWebModule
} from "../src/types";
import {
hasUiCapability,
moduleInstalled,
moduleIntegrationEnabled,
routeContributionsForModules,
uiCapability
} from "../src/platform/moduleLogic";
import { scopeGrants } from "../src/utils/permissions";
function assert(condition: unknown, message: string): void {
if (!condition) throw new Error(message);
}
const access: PlatformWebModule = { id: "access", label: "Access", version: "test" };
const filesCapability = { kind: "fileExplorer" };
const mailCapability = { kind: "mailProfiles" };
const files: PlatformWebModule = {
id: "files",
label: "Files",
version: "test",
routes: [{ path: "/files", order: 20, render: () => null }],
uiCapabilities: { "files.fileExplorer": filesCapability }
};
const mail: PlatformWebModule = {
id: "mail",
label: "Mail",
version: "test",
routes: [{ path: "/mail", order: 30, render: () => null }],
uiCapabilities: { "mail.profiles": mailCapability }
};
const campaigns: PlatformWebModule = {
id: "campaigns",
label: "Campaigns",
version: "test",
dependencies: ["access"],
optionalDependencies: ["files", "mail"],
routes: [{ path: "/campaigns", order: 10, render: () => null }]
};
const cases: Array<{ name: string; modules: PlatformWebModule[]; files: boolean; mail: boolean }> = [
{ name: "core-only", modules: [access], files: false, mail: false },
{ name: "files-only", modules: [access, files], files: true, mail: false },
{ name: "mail-only", modules: [access, mail], files: false, mail: true },
{ name: "campaign-only", modules: [access, campaigns], files: false, mail: false },
{ name: "campaign-files", modules: [access, campaigns, files], files: true, mail: false },
{ name: "campaign-mail", modules: [access, campaigns, mail], files: false, mail: true },
{ name: "full-product", modules: [access, campaigns, files, mail], files: true, mail: true }
];
for (const testCase of cases) {
const campaignInstalled = moduleInstalled("campaigns", testCase.modules);
assert(moduleInstalled("access", testCase.modules), `${testCase.name}: access should be installed`);
assert(moduleInstalled("files", testCase.modules) === testCase.files, `${testCase.name}: files installed state`);
assert(moduleInstalled("mail", testCase.modules) === testCase.mail, `${testCase.name}: mail installed state`);
assert(hasUiCapability("files.fileExplorer", testCase.modules) === testCase.files, `${testCase.name}: files UI capability`);
assert(hasUiCapability("mail.profiles", testCase.modules) === testCase.mail, `${testCase.name}: mail UI capability`);
assert(moduleIntegrationEnabled("campaigns", "files", testCase.modules) === (campaignInstalled && testCase.files), `${testCase.name}: campaign files integration`);
assert(moduleIntegrationEnabled("campaigns", "mail", testCase.modules) === (campaignInstalled && testCase.mail), `${testCase.name}: campaign mail integration`);
}
assert(uiCapability("files.fileExplorer", [access, files]) === filesCapability, "files capability should return the module-provided object");
assert(uiCapability("mail.profiles", [access, mail]) === mailCapability, "mail capability should return the module-provided object");
const routes = routeContributionsForModules([access, files, mail, campaigns]).map((route) => route.path);
assert(routes.join(",") === "/campaigns,/files,/mail", "routes should aggregate and sort by contribution order");
assert(scopeGrants("tenant:*", "calendar:event:read"), "tenant wildcard should grant tenant-level module scopes");
assert(!scopeGrants("tenant:*", "system:settings:read"), "tenant wildcard should not grant system scopes");
let selectedFunctionId = "";
const functionAction: OrganizationFunctionActionContribution = {
id: "test.view-assignments",
label: "View assignments",
icon: "assignments-icon",
order: 40,
anyOf: ["idm:organization_assignment:read"],
onClick: (context) => {
selectedFunctionId = context.function.id;
}
};
functionAction.onClick({
settings: { apiBaseUrl: "", apiKey: "", accessToken: "" },
auth: {} as OrganizationFunctionActionContext["auth"],
function: {
id: "function-1",
tenant_id: "tenant-1",
organization_unit_id: "unit-1",
slug: "test-function",
name: "Test function"
}
});
assert(selectedFunctionId === "function-1", "organization function actions receive their row context");
assert(!("render" in functionAction), "organization function actions expose metadata instead of arbitrary rendered controls");