import { describe, expect, it } from "vitest"; import { projectHealth } from "../src/services/projectHealthSemantics.js"; const finding = (severity = "warning", status = "new") => ({ severity, status }); const health = (repositoryFindings: ReturnType[] = [], syncStatuses: string[] = ["ready"]) => projectHealth({ repositoryFindings, giteaRepositories: syncStatuses.map((syncStatus) => ({ syncStatus })) }); describe("project health semantics", () => { it("does not label a returned warning such as branch sprawl as a critical risk", () => { expect(health([finding("warning", "regressed")])).toEqual({ score: 80, healthStatus: "warn", activeFindingCount: 1, criticalCount: 0, warningCount: 1, regressedCount: 1, }); }); it.each(["new", "triaged", "regressed", "issue_open"])("preserves critical failures in status %s", (status) => { expect(health([finding("critical", status)]).healthStatus).toBe("risk"); }); it("preserves aggregate low-score risk without a critical finding", () => { expect(health(Array.from({ length: 11 }, () => finding()))).toMatchObject({ score: 45, healthStatus: "risk" }); expect(health(Array.from({ length: 10 }, () => finding()))).toMatchObject({ score: 50, healthStatus: "warn" }); }); it("retains recurrence evidence and its aggregate penalty", () => { expect(health(Array.from({ length: 3 }, () => finding("warning", "regressed")))).toMatchObject({ score: 40, healthStatus: "risk", regressedCount: 3, warningCount: 3, }); expect(health([finding("info", "regressed")])).toMatchObject({ score: 85, healthStatus: "warn", regressedCount: 1 }); }); it("excludes resolved and suppressed findings without hiding active findings", () => { expect(health([finding("critical", "resolved"), finding("critical", "suppressed"), finding("info")])).toMatchObject({ score: 100, healthStatus: "healthy", activeFindingCount: 1, criticalCount: 0, }); }); it("retains repository availability penalties and bounded scores", () => { expect(health([], ["failed"])).toMatchObject({ score: 80, healthStatus: "warn" }); expect(health(Array.from({ length: 10 }, () => finding("critical")), ["failed", "failed", "failed"])).toMatchObject({ score: 0, healthStatus: "risk", }); expect(health()).toMatchObject({ score: 100, healthStatus: "healthy" }); }); });