import { describe, expect, it } from "vitest"; import { readFileSync } from "node:fs"; import { resolve } from "node:path"; const readRouter = () => readFileSync(resolve(__dirname, "./router/index.ts"), "utf8"); describe("admin project route permissions", () => { it("lets any authorized project role open the project management detail page", () => { const source = readRouter(); expect(source).toContain('name: "AdminProjectDetail"'); expect(source).toContain("requiresProjectMember: true"); expect(source).not.toContain("meta: { title: TEXT.modules.adminProjects.detailTitle, requiresAdmin: true }"); expect(source).toContain("ensureRouteProjectMember(to, studyStore)"); }); it("allows project admin pages through matrix-authorized PMs instead of all project roles", () => { const source = readRouter(); expect(source).toContain('adminProjectPermission: { module: "sites", action: "read" }'); expect(source).toContain('adminProjectPermission: { module: "audit_export", action: "read" }'); expect(source).toContain("meta: { title: TEXT.menu.projectManagement }"); expect(source).toContain("ADMIN_PROJECT_OPERATION_KEYS"); expect(source).toContain('if (role !== "PM") return false;'); expect(source).toContain("isApiPermissionAllowed"); expect(source).toContain("studyStore.currentPermissions?.[role]?.[operationKey]"); }); it("guards project permission configuration with the system-level project config permission", () => { const source = readRouter(); const projectPermissionRouteStart = source.indexOf('name: "AdminPermissionsProject"'); const projectPermissionRouteEnd = source.indexOf('name: "AdminPermissionsMonitoring"', projectPermissionRouteStart); const projectPermissionRoute = source.slice(projectPermissionRouteStart, projectPermissionRouteEnd); expect(source).toContain('const SYSTEM_PERMISSION_PROJECT_CONFIG = "system:permissions:project_config";'); expect(projectPermissionRoute).toContain("systemPermission: SYSTEM_PERMISSION_PROJECT_CONFIG"); expect(projectPermissionRoute).not.toContain("requiresProjectPm: true"); expect(source).toContain("to.meta.systemPermission"); expect(source).toContain("hasSystemPermissionAccess(to.meta.systemPermission as string, isAdmin)"); }); it("keeps login landing independent from PM management backend access", () => { const source = readRouter(); expect(source).not.toContain("findPmAdminLandingPath"); expect(source).not.toContain("pmAdminLandingModules"); expect(source).toContain(' : studyStore.currentStudy\n ? "/project/overview"\n : "/admin/projects",'); }); it("does not register the removed non-admin personal dashboard route", () => { const source = readRouter(); const removedComponent = ["My", "Work", "bench"].join(""); const removedPath = `/${["work", "bench"].join("")}`; expect(source).not.toContain(removedComponent); expect(source).not.toContain(`path: "${removedPath.slice(1)}"`); expect(source).not.toContain(`"${removedPath}"`); }); it("does not register legacy finance contract routes", () => { const source = readRouter(); expect(source).not.toContain("FinanceContracts"); expect(source).not.toContain("FinanceContract"); expect(source).not.toContain("finance/contracts"); }); it("does not register standalone contract fee create or edit pages", () => { const source = readRouter(); expect(source).not.toContain("FeeContractForm"); expect(source).not.toContain('name: "FeeContractNew"'); expect(source).not.toContain('name: "FeeContractEdit"'); expect(source).not.toContain('path: "fees/contracts/new"'); expect(source).not.toContain('path: "fees/contracts/:contractId/edit"'); }); it("does not register standalone startup auth edit pages", () => { const source = readRouter(); expect(source).not.toContain('name: "StartupKickoffEdit"'); expect(source).not.toContain('name: "StartupTrainingEdit"'); expect(source).not.toContain('name: "StartupTrainingNew"'); expect(source).not.toContain('path: "startup/kickoff/:meetingId/edit"'); expect(source).not.toContain('path: "startup/training/new"'); expect(source).not.toContain('path: "startup/training/:recordId/edit"'); }); it("uses precautions routes instead of knowledge note routes", () => { const source = readRouter(); expect(source).toContain('path: "knowledge/precautions"'); expect(source).toContain('path: "knowledge/precautions/new"'); expect(source).toContain('path: "knowledge/precautions/:id"'); expect(source).toContain('path: "knowledge/precautions/:id/edit"'); expect(source).not.toContain("KnowledgeNote"); expect(source).not.toContain("/knowledge/notes"); }); });