Some checks are pending
CI / verify (push) Waiting to run
Make demo search, filters, exports, and controls functional while exposing dedicated KPI detail pages with tested breakdowns. Co-authored-by: Cursor <cursoragent@cursor.com>
44 lines
1.9 KiB
TypeScript
44 lines
1.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { getDashboardData, getMetricDetails } from "@/domain/analytics";
|
|
|
|
describe("metric drill-down analytics", () => {
|
|
const dashboard = getDashboardData();
|
|
const details = getMetricDetails();
|
|
|
|
it("reconciles inventory value with batch totals", () => {
|
|
expect(details.inventoryValue.retailValue).toBe(dashboard.metrics.retailValue);
|
|
expect(details.inventoryValue.costValue).toBe(
|
|
dashboard.inventory.reduce((sum, item) => sum + item.costExposure, 0),
|
|
);
|
|
expect(details.inventoryValue.potentialMargin).toBe(
|
|
details.inventoryValue.retailValue - details.inventoryValue.costValue,
|
|
);
|
|
expect(details.inventoryValue.byBranch).toHaveLength(4);
|
|
});
|
|
|
|
it("uses complete current and prior revenue periods", () => {
|
|
expect(details.revenue.current30d).toBe(dashboard.metrics.revenue30d);
|
|
expect(details.revenue.current30d).toBeGreaterThan(0);
|
|
expect(details.revenue.prior30d).toBeGreaterThan(0);
|
|
expect(Number.isFinite(details.revenue.changePercent)).toBe(true);
|
|
expect(details.revenue.byProduct).toHaveLength(8);
|
|
});
|
|
|
|
it("limits headline risk exposure to at-risk and expired batches", () => {
|
|
expect(details.risk.affected.every(
|
|
(item) => item.status === "at_risk" || item.status === "expired",
|
|
)).toBe(true);
|
|
expect(details.risk.costValue).toBe(dashboard.metrics.atRiskValue);
|
|
expect(details.risk.byStatus.some((row) => row.status === "watch")).toBe(true);
|
|
});
|
|
|
|
it("provides bounded freshness rollups", () => {
|
|
expect(details.freshness.averageScore).toBe(dashboard.metrics.averageFreshness);
|
|
expect(details.freshness.weightedScore).toBeGreaterThanOrEqual(0);
|
|
expect(details.freshness.weightedScore).toBeLessThanOrEqual(100);
|
|
expect(details.freshness.freshUnitsPercent).toBeGreaterThanOrEqual(0);
|
|
expect(details.freshness.freshUnitsPercent).toBeLessThanOrEqual(100);
|
|
expect(details.freshness.byProduct).toHaveLength(8);
|
|
});
|
|
});
|