test(api): cover assistant dashboard overview reads
This commit is contained in:
@@ -0,0 +1,77 @@
|
|||||||
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import { SystemRole } from "@capakraken/shared";
|
||||||
|
|
||||||
|
import {
|
||||||
|
createToolContext,
|
||||||
|
executeTool,
|
||||||
|
getDashboardOverview,
|
||||||
|
} from "./assistant-tools-dashboard-test-helpers.js";
|
||||||
|
|
||||||
|
describe("assistant dashboard tools overview", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("routes statistics through the dashboard overview path", async () => {
|
||||||
|
vi.mocked(getDashboardOverview).mockResolvedValue({
|
||||||
|
totalResources: 12,
|
||||||
|
activeResources: 10,
|
||||||
|
inactiveResources: 2,
|
||||||
|
totalProjects: 7,
|
||||||
|
activeProjects: 4,
|
||||||
|
inactiveProjects: 3,
|
||||||
|
totalAllocations: 21,
|
||||||
|
activeAllocations: 18,
|
||||||
|
cancelledAllocations: 3,
|
||||||
|
approvedVacations: 6,
|
||||||
|
totalEstimates: 9,
|
||||||
|
budgetSummary: {
|
||||||
|
totalBudgetCents: 1_234_56,
|
||||||
|
totalCostCents: 654_32,
|
||||||
|
avgUtilizationPercent: 53,
|
||||||
|
},
|
||||||
|
budgetBasis: {
|
||||||
|
remainingBudgetCents: 58_024,
|
||||||
|
budgetedProjects: 5,
|
||||||
|
unbudgetedProjects: 2,
|
||||||
|
trackedAssignmentCount: 18,
|
||||||
|
windowStart: null,
|
||||||
|
windowEnd: null,
|
||||||
|
},
|
||||||
|
projectsByStatus: [
|
||||||
|
{ status: "ACTIVE", count: 4 },
|
||||||
|
{ status: "DRAFT", count: 2 },
|
||||||
|
{ status: "DONE", count: 1 },
|
||||||
|
],
|
||||||
|
chapterUtilization: [
|
||||||
|
{ chapter: "CGI", resourceCount: 5, avgChargeabilityTarget: 78 },
|
||||||
|
{ chapter: "Compositing", resourceCount: 3, avgChargeabilityTarget: 74 },
|
||||||
|
{ chapter: "Unassigned", resourceCount: 2, avgChargeabilityTarget: 0 },
|
||||||
|
],
|
||||||
|
recentActivity: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const ctx = createToolContext({}, { userRole: SystemRole.CONTROLLER });
|
||||||
|
const result = await executeTool("get_statistics", "{}", ctx);
|
||||||
|
|
||||||
|
expect(JSON.parse(result.content)).toEqual({
|
||||||
|
activeResources: 10,
|
||||||
|
totalProjects: 7,
|
||||||
|
activeProjects: 4,
|
||||||
|
totalAllocations: 21,
|
||||||
|
approvedVacations: 6,
|
||||||
|
totalEstimates: 9,
|
||||||
|
totalBudget: "1.234,56 EUR",
|
||||||
|
projectsByStatus: {
|
||||||
|
ACTIVE: 4,
|
||||||
|
DRAFT: 2,
|
||||||
|
DONE: 1,
|
||||||
|
},
|
||||||
|
topChapters: [
|
||||||
|
{ chapter: "CGI", count: 5 },
|
||||||
|
{ chapter: "Compositing", count: 3 },
|
||||||
|
{ chapter: "Unassigned", count: 2 },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import { SystemRole } from "@capakraken/shared";
|
||||||
|
|
||||||
|
import {
|
||||||
|
createToolContext,
|
||||||
|
executeTool,
|
||||||
|
getDashboardProjectHealth,
|
||||||
|
} from "./assistant-tools-dashboard-test-helpers.js";
|
||||||
|
|
||||||
|
describe("assistant dashboard tools project health", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("routes project health reads through the dashboard router path", async () => {
|
||||||
|
vi.mocked(getDashboardProjectHealth).mockResolvedValue([
|
||||||
|
{
|
||||||
|
id: "project_1",
|
||||||
|
projectName: "Apollo",
|
||||||
|
shortCode: "APL",
|
||||||
|
status: "ACTIVE",
|
||||||
|
clientId: "client_1",
|
||||||
|
clientName: "Acme Mobility",
|
||||||
|
budgetHealth: 74,
|
||||||
|
staffingHealth: 88,
|
||||||
|
timelineHealth: 63,
|
||||||
|
compositeScore: 75,
|
||||||
|
budgetCents: 250_000,
|
||||||
|
spentCents: 180_000,
|
||||||
|
remainingBudgetCents: 70_000,
|
||||||
|
budgetUtilizationPercent: 72,
|
||||||
|
demandHeadcountTotal: 6,
|
||||||
|
demandHeadcountFilled: 5,
|
||||||
|
demandHeadcountOpen: 1,
|
||||||
|
demandRequirementCount: 3,
|
||||||
|
plannedEndDate: new Date("2026-08-31T00:00:00.000Z"),
|
||||||
|
daysUntilEndDate: 45,
|
||||||
|
timelineStatus: "ON_TRACK",
|
||||||
|
calendarLocations: [
|
||||||
|
{
|
||||||
|
countryCode: "DE",
|
||||||
|
countryName: "Germany",
|
||||||
|
federalState: "BY",
|
||||||
|
metroCityName: "Munich",
|
||||||
|
assignmentCount: 3,
|
||||||
|
spentCents: 120_000,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
derivation: {
|
||||||
|
periodStart: "2026-08-01",
|
||||||
|
periodEnd: "2026-08-31",
|
||||||
|
calendarContextCount: 1,
|
||||||
|
holidayAwareAssignmentCount: 3,
|
||||||
|
fallbackAssignmentCount: 0,
|
||||||
|
baseSpentCents: 190_000,
|
||||||
|
adjustedSpentCents: 180_000,
|
||||||
|
publicHolidayDayEquivalent: 1,
|
||||||
|
publicHolidayCostDeductionCents: 6_000,
|
||||||
|
absenceDayEquivalent: 0.5,
|
||||||
|
absenceCostDeductionCents: 4_000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const ctx = createToolContext({}, { userRole: SystemRole.CONTROLLER });
|
||||||
|
const result = await executeTool("get_project_health", "{}", ctx);
|
||||||
|
|
||||||
|
expect(getDashboardProjectHealth).toHaveBeenCalledTimes(1);
|
||||||
|
expect(JSON.parse(result.content)).toEqual({
|
||||||
|
projects: [
|
||||||
|
{
|
||||||
|
projectId: "project_1",
|
||||||
|
projectName: "Apollo",
|
||||||
|
shortCode: "APL",
|
||||||
|
status: "ACTIVE",
|
||||||
|
overall: 75,
|
||||||
|
budget: 74,
|
||||||
|
staffing: 88,
|
||||||
|
timeline: 63,
|
||||||
|
rating: "at_risk",
|
||||||
|
budgetBasis: {
|
||||||
|
budgetCents: 250_000,
|
||||||
|
spentCents: 180_000,
|
||||||
|
remainingBudgetCents: 70_000,
|
||||||
|
budgetUtilizationPercent: 72,
|
||||||
|
calendarLocations: [
|
||||||
|
{
|
||||||
|
countryCode: "DE",
|
||||||
|
countryName: "Germany",
|
||||||
|
federalState: "BY",
|
||||||
|
metroCityName: "Munich",
|
||||||
|
assignmentCount: 3,
|
||||||
|
spentCents: 120_000,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
derivation: {
|
||||||
|
periodStart: "2026-08-01",
|
||||||
|
periodEnd: "2026-08-31",
|
||||||
|
calendarContextCount: 1,
|
||||||
|
holidayAwareAssignmentCount: 3,
|
||||||
|
fallbackAssignmentCount: 0,
|
||||||
|
baseSpentCents: 190_000,
|
||||||
|
adjustedSpentCents: 180_000,
|
||||||
|
publicHolidayDayEquivalent: 1,
|
||||||
|
publicHolidayCostDeductionCents: 6_000,
|
||||||
|
absenceDayEquivalent: 0.5,
|
||||||
|
absenceCostDeductionCents: 4_000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
staffingBasis: {
|
||||||
|
demandHeadcountTotal: 6,
|
||||||
|
demandHeadcountFilled: 5,
|
||||||
|
demandHeadcountOpen: 1,
|
||||||
|
demandRequirementCount: 3,
|
||||||
|
},
|
||||||
|
timelineBasis: {
|
||||||
|
plannedEndDate: "2026-08-31T00:00:00.000Z",
|
||||||
|
daysUntilEndDate: 45,
|
||||||
|
timelineStatus: "ON_TRACK",
|
||||||
|
},
|
||||||
|
context: {
|
||||||
|
clientId: "client_1",
|
||||||
|
clientName: "Acme Mobility",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
summary: {
|
||||||
|
healthy: 0,
|
||||||
|
atRisk: 1,
|
||||||
|
critical: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user