Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/apps/web/app/services/admin/admin-dashboard-personalization.server.test.ts
T

136 lines
4.7 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from "vitest";
import type { AdminDashboardDataSources } from "./admin-dashboard-personalization.server";
import {
loadPersonalizedAdminDashboard,
selectAdminDashboardWidgetIds,
} from "./admin-dashboard-personalization.server";
const sources = {
salesOwn: vi.fn(async () => [
{ id: "sales_today" as const, value: "2", href: "/sales/tasks/today" },
{ id: "sales_own_pipeline" as const, value: "10 €", href: "/sales/deals" },
{ id: "sales_appointments" as const, value: "1", href: "/sales/bookings" },
{ id: "sales_followups" as const, value: "3", href: "/sales/tasks/today" },
]),
salesTeam: vi.fn(async () => [
{ id: "sales_team_pipeline" as const, value: "20 €", href: "/sales/deals" },
{ id: "sales_unassigned_leads" as const, value: "4", href: "/leads" },
{ id: "sales_team_activity" as const, value: "5", href: "/sales/tasks/today" },
]),
support: vi.fn(async () => [
{ id: "support_inbox" as const, value: "6", href: "/support" },
{ id: "support_customer_events" as const, value: "7", href: "/audit" },
]),
engineering: vi.fn(async () => [
{ id: "engineering_health" as const, value: "OK", href: "/system" },
{ id: "engineering_queues" as const, value: "0", href: "/system/jobs" },
{ id: "engineering_errors" as const, value: "0", href: "/events" },
{ id: "engineering_deploy" as const, value: "abc123", href: "/system/deploys" },
]),
executive: vi.fn(async () => [
{ id: "executive_forecast" as const, value: "1 €", href: "/sales/deals" },
{ id: "executive_revenue" as const, value: "2 €", href: "/sales/deals" },
{ id: "executive_mrr" as const, value: "3 €", href: "/dashboard" },
{ id: "executive_arr" as const, value: "36 €", href: "/dashboard" },
{ id: "executive_churn" as const, value: "0 %", href: "/dashboard" },
]),
} satisfies AdminDashboardDataSources;
describe("admin dashboard personalization", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("unions combined role widgets without duplicates", () => {
const ids = selectAdminDashboardWidgetIds({
roleKeys: ["sales", "sales_manager", "sales"],
permissions: [
"admin_sales.crm.read",
"admin_sales.crm.read_all",
"admin_sales.booking.manage",
"admin_sales.reporting.read_all",
],
});
expect(ids).toEqual([
"sales_own_pipeline",
"sales_today",
"sales_appointments",
"sales_followups",
"sales_team_pipeline",
"sales_unassigned_leads",
"sales_team_activity",
]);
});
it("loads only the data sources selected by roles and effective permissions", async () => {
const vm = await loadPersonalizedAdminDashboard(
{
adminUserId: "admin_sales",
roleKeys: ["sales"],
permissions: [
"admin.dashboard.view",
"admin_sales.crm.read",
"admin_sales.booking.manage",
],
now: new Date("2026-07-26T08:00:00.000Z"),
locale: "en",
},
sources
);
expect(sources.salesOwn).toHaveBeenCalledOnce();
expect(sources.salesOwn).toHaveBeenCalledWith(
expect.objectContaining({ locale: "en" })
);
expect(sources.salesTeam).not.toHaveBeenCalled();
expect(sources.support).not.toHaveBeenCalled();
expect(sources.engineering).not.toHaveBeenCalled();
expect(sources.executive).not.toHaveBeenCalled();
expect(vm.widgets.map((entry) => entry.id)).toEqual([
"sales_own_pipeline",
"sales_today",
"sales_appointments",
"sales_followups",
]);
});
it("does not query a role source after its effective permission is removed", async () => {
const vm = await loadPersonalizedAdminDashboard(
{
adminUserId: "admin_support",
roleKeys: ["support"],
permissions: ["admin.dashboard.view"],
},
sources
);
expect(sources.support).not.toHaveBeenCalled();
expect(vm.widgets).toEqual([]);
});
it("loads combined role sources once each", async () => {
const vm = await loadPersonalizedAdminDashboard(
{
adminUserId: "admin_combined",
roleKeys: ["support", "engineering"],
permissions: [
"admin.dashboard.view",
"admin_identity.impersonation.start",
"admin.metrics.view",
"admin.events.view",
],
},
sources
);
expect(sources.support).toHaveBeenCalledOnce();
expect(sources.engineering).toHaveBeenCalledOnce();
expect(new Set(vm.widgets.map((entry) => entry.id)).size).toBe(
vm.widgets.length
);
expect(sources.salesOwn).not.toHaveBeenCalled();
expect(sources.executive).not.toHaveBeenCalled();
});
});