文件
hyb-oa/server/tests/unit/workspaceSettings.navigation.test.js
T

210 行
7.1 KiB
JavaScript

const {
DEFAULT_MODULE_VISIBILITY,
buildDefaultWorkspaceSetting,
getSystemNavigation,
normalizeModuleVisibilityJson,
} = require("../../src/services/workspaceSettings");
const { hasPermission, resolvePermissionsForRoles } = require("../../src/constants/permissions");
function buildPrisma(enabledFlagKeys = []) {
const enabled = new Set(enabledFlagKeys);
return {
workspaceSetting: {
findFirst: vi.fn().mockResolvedValue(null),
},
featureFlag: {
findUnique: vi.fn().mockImplementation(async ({ where }) => {
if (!enabled.has(where.flag_key)) {
return null;
}
return {
id: `flag-${where.flag_key}`,
flag_key: where.flag_key,
override_mode: "force_on",
rollout_type: "global",
department_ids: [],
note: "",
version: 1,
created_at: null,
created_by: null,
updated_at: null,
updated_by: null,
};
}),
},
};
}
function buildConfig() {
return {
announcementsEnabled: false,
attendanceEnabled: false,
budgetPrecheckEnabled: false,
cutoverConsoleEnabled: false,
employeeLifecycleEnabled: false,
globalSearchEnabled: false,
paymentBatchEnabled: false,
portalHomeEnabled: false,
presenceBoardEnabled: false,
projectDomainEnabled: false,
projectLinkingEnabled: false,
todoBoardEnabled: false,
weeklyReportEnabled: false,
workflowDefinitionAdminEnabled: false,
};
}
describe("workspace small-team navigation defaults", () => {
it("keeps only the small-team task path in default main navigation", () => {
const mainModules = Object.entries(DEFAULT_MODULE_VISIBILITY)
.filter(([, placement]) => placement === "main")
.map(([key]) => key);
expect(mainModules).toEqual([
"portal",
"team",
"leaveRequests",
"reimbursements",
"assets",
"projects",
"contractsRegistry",
"purchaseRequests",
]);
expect(DEFAULT_MODULE_VISIBILITY.todos).toBe("hidden");
expect(DEFAULT_MODULE_VISIBILITY.assets).toBe("main");
expect(DEFAULT_MODULE_VISIBILITY.contractsRegistry).toBe("main");
expect(DEFAULT_MODULE_VISIBILITY.purchaseRequests).toBe("main");
expect(DEFAULT_MODULE_VISIBILITY.attendance).toBe("hidden");
});
it("normalizes unknown or invalid module visibility back to the R66 defaults", () => {
const normalized = normalizeModuleVisibilityJson({
attendance: "main",
purchaseRequests: "hidden",
unknownModule: "main",
budgets: "invalid",
});
expect(normalized.attendance).toBe("main");
expect(normalized.purchaseRequests).toBe("hidden");
expect(normalized.budgets).toBe(DEFAULT_MODULE_VISIBILITY.budgets);
expect(normalized.unknownModule).toBeUndefined();
});
it("builds a small-team internal workspace by default", () => {
const workspace = buildDefaultWorkspaceSetting();
expect(workspace.profile).toBe("small_team_internal");
expect(workspace.moduleVisibility.attendance).toBe("hidden");
});
it("keeps low-frequency and finance-only modules out of employee primary navigation", async () => {
const employee = {
id: "employee-1",
department_id: "dept-1",
roleCodes: ["employee"],
permissionCodes: resolvePermissionsForRoles(["employee"]),
};
const navigation = await getSystemNavigation({
prisma: buildPrisma(["presence_board_v1", "project_domain_v1"]),
config: { ...buildConfig(), projectDomainEnabled: true },
employee,
hasPermission: (candidate, permissionCode) => hasPermission(candidate.permissionCodes, permissionCode),
});
const mainLabels = navigation.sections.main.map((item) => item.label);
expect(mainLabels).toEqual(["工作台", "报销", "采购", "项目", "资产", "请假记录"]);
expect(mainLabels).not.toContain("待我处理");
expect(mainLabels).not.toContain("票据");
expect(mainLabels).not.toContain("个人设置");
const backupKeys = navigation.sections.backup.map((item) => item.key);
expect(backupKeys).not.toContain("purchaseRequests");
expect(backupKeys).not.toContain("travelRequests");
expect(backupKeys).not.toContain("invoicePool");
expect(backupKeys).not.toContain("contractsRegistry");
expect(backupKeys).not.toContain("budgets");
expect(backupKeys).not.toContain("paymentBatches");
expect(backupKeys).not.toContain("apOperations");
expect(backupKeys).not.toContain("erpIntegrations");
expect(backupKeys).not.toContain("dashboard");
});
it("shows待我处理 for business approvers and keeps admin-only users out", async () => {
const manager = {
id: "manager-1",
department_id: "dept-1",
roleCodes: ["manager"],
permissionCodes: resolvePermissionsForRoles(["manager"]),
};
const managerNavigation = await getSystemNavigation({
prisma: buildPrisma(["presence_board_v1", "project_domain_v1", "project_linking_v1"]),
config: { ...buildConfig(), projectDomainEnabled: true, projectLinkingEnabled: true, presenceBoardEnabled: true },
employee: manager,
hasPermission: (candidate, permissionCode) => hasPermission(candidate.permissionCodes, permissionCode),
});
expect(managerNavigation.sections.main.map((item) => item.label)).toEqual([
"工作台",
"待我处理",
"报销",
"采购",
"合同",
"项目",
"资产",
"团队",
"请假记录",
]);
const adminOnly = {
id: "admin-1",
department_id: "dept-1",
roleCodes: ["admin"],
permissionCodes: resolvePermissionsForRoles(["admin"]),
};
const navigation = await getSystemNavigation({
prisma: buildPrisma(["payment_batch_v1"]),
config: { ...buildConfig(), workflowDefinitionAdminEnabled: true },
employee: adminOnly,
hasPermission: (candidate, permissionCode) => hasPermission(candidate.permissionCodes, permissionCode),
});
const allKeys = [
...navigation.sections.main,
...navigation.sections.admin,
...navigation.sections.backup,
].map((item) => item.key);
expect(allKeys).toContain("systemSettings");
expect(allKeys).not.toContain("auditLogs");
expect(allKeys).not.toContain("workflowTasks");
});
it("uses work names for finance navigation", async () => {
const finance = {
id: "finance-1",
department_id: "dept-1",
roleCodes: ["finance"],
permissionCodes: resolvePermissionsForRoles(["finance"]),
};
const navigation = await getSystemNavigation({
prisma: buildPrisma(["payment_batch_v1"]),
config: { ...buildConfig(), paymentBatchEnabled: true },
employee: finance,
hasPermission: (candidate, permissionCode) => hasPermission(candidate.permissionCodes, permissionCode),
});
const mainLabels = navigation.sections.main.map((item) => item.label);
expect(mainLabels).toContain("待我处理");
expect(mainLabels).toContain("付款");
expect(mainLabels).toContain("应付账款");
expect(mainLabels).toContain("票据");
expect(mainLabels).not.toContain("AP 运营");
expect(mainLabels).not.toContain("付款批次");
});
});