127 lines
4.3 KiB
TypeScript
127 lines
4.3 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { buildAssistantInsight } from "../router/assistant-insights.js";
|
|
|
|
describe("assistant insights", () => {
|
|
it("builds a transparent chargeability insight from holiday-aware payloads", () => {
|
|
const insight = buildAssistantInsight("get_chargeability", {
|
|
resource: "Bruce Banner",
|
|
month: "2026-01",
|
|
chargeability: "42.9%",
|
|
chargeabilityPct: 42.9,
|
|
targetPct: 80,
|
|
availableHours: 168,
|
|
bookedHours: 72,
|
|
unassignedHours: 96,
|
|
targetHours: 134.4,
|
|
baseWorkingDays: 23,
|
|
workingDays: 21,
|
|
baseAvailableHours: 184,
|
|
locationContext: { country: "Deutschland", federalState: "BY", metroCity: "Augsburg" },
|
|
holidaySummary: { count: 2, workdayCount: 2, hoursDeduction: 16 },
|
|
absenceSummary: { dayEquivalent: 0.5, hoursDeduction: 4 },
|
|
});
|
|
|
|
expect(insight).toEqual(
|
|
expect.objectContaining({
|
|
kind: "chargeability",
|
|
title: "Bruce Banner · 2026-01",
|
|
metrics: expect.arrayContaining([
|
|
expect.objectContaining({ label: "Chargeability", value: "42.9%", tone: "warn" }),
|
|
expect.objectContaining({ label: "Available", value: "168 h" }),
|
|
expect.objectContaining({ label: "Target", value: "134.4 h" }),
|
|
]),
|
|
sections: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
title: "Basis",
|
|
metrics: expect.arrayContaining([
|
|
expect.objectContaining({ label: "Location", value: "Augsburg, BY, Deutschland" }),
|
|
]),
|
|
}),
|
|
expect.objectContaining({
|
|
title: "Deductions",
|
|
metrics: expect.arrayContaining([
|
|
expect.objectContaining({ label: "Holiday deduction", value: "16 h" }),
|
|
expect.objectContaining({ label: "Absence deduction", value: "4 h" }),
|
|
]),
|
|
}),
|
|
]),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("builds a holiday comparison insight with regional scope counts", () => {
|
|
const insight = buildAssistantInsight("list_holidays_by_region", {
|
|
locationContext: { countryCode: "DE", federalState: "BY" },
|
|
count: 14,
|
|
periodStart: "2026-01-01",
|
|
periodEnd: "2026-12-31",
|
|
summary: {
|
|
byScope: [
|
|
{ scope: "NATIONAL", count: 9 },
|
|
{ scope: "STATE", count: 5 },
|
|
],
|
|
},
|
|
});
|
|
|
|
expect(insight).toEqual(
|
|
expect.objectContaining({
|
|
kind: "holiday_region",
|
|
title: "BY, DE",
|
|
metrics: expect.arrayContaining([
|
|
expect.objectContaining({ label: "Resolved holidays", value: "14" }),
|
|
]),
|
|
sections: [
|
|
expect.objectContaining({
|
|
title: "Scopes",
|
|
metrics: expect.arrayContaining([
|
|
expect.objectContaining({ label: "STATE", value: "5" }),
|
|
]),
|
|
}),
|
|
],
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("builds a best-resource insight from staffing recommendations", () => {
|
|
const insight = buildAssistantInsight("find_best_project_resource", {
|
|
project: { name: "Gelddruckmaschine", shortCode: "GDM" },
|
|
period: { startDate: "2026-04-01", endDate: "2026-04-21", minHoursPerDay: 3, rankingMode: "lowest_lcr" },
|
|
candidateCount: 4,
|
|
bestMatch: {
|
|
name: "Jane Doe",
|
|
role: "TD",
|
|
chapter: "Lighting",
|
|
country: "Deutschland",
|
|
federalState: "BY",
|
|
metroCity: "Muenchen",
|
|
lcr: "€85.00",
|
|
remainingHours: 74,
|
|
remainingHoursPerDay: 3.5,
|
|
availableHours: 120,
|
|
baseAvailableHours: 136,
|
|
holidaySummary: { hoursDeduction: 8 },
|
|
absenceSummary: { hoursDeduction: 0 },
|
|
},
|
|
});
|
|
|
|
expect(insight).toEqual(
|
|
expect.objectContaining({
|
|
kind: "resource_match",
|
|
title: "GDM staffing",
|
|
metrics: expect.arrayContaining([
|
|
expect.objectContaining({ label: "Best match", value: "Jane Doe" }),
|
|
expect.objectContaining({ label: "Remaining", value: "74 h", tone: "good" }),
|
|
]),
|
|
sections: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
title: "Selection",
|
|
metrics: expect.arrayContaining([
|
|
expect.objectContaining({ label: "Location", value: "Muenchen, BY, Deutschland" }),
|
|
]),
|
|
}),
|
|
]),
|
|
}),
|
|
);
|
|
});
|
|
});
|