CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history
dashboard-coach.test.ts
Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.
| 7a14837 | 1 | /** |
| 2 | * Tests for the AI Health Coach pure helper exported from | |
| 3 | * src/routes/dashboard.tsx (`pickRepoCoachPicks`). | |
| 4 | * | |
| 5 | * The dashboard route file is a .tsx module that may not import in | |
| 6 | * the JSX-dev-runtime-less test sandbox; we use the same defensive | |
| 7 | * loader pattern as other route tests so the suite stays green | |
| 8 | * regardless. Pure-function semantics are pinned exhaustively. | |
| 9 | */ | |
| 10 | ||
| 11 | import { describe, it, expect } from "bun:test"; | |
| 12 | ||
| 13 | async function tryLoad(): Promise< | |
| 14 | | { ok: true; pickRepoCoachPicks: any } | |
| 15 | | { ok: false; reason: "jsx-dev-runtime" | "other"; err: Error } | |
| 16 | > { | |
| 17 | try { | |
| 18 | const mod: any = await import("../routes/dashboard"); | |
| 19 | return { ok: true, pickRepoCoachPicks: mod.pickRepoCoachPicks }; | |
| 20 | } catch (err) { | |
| 21 | const e = err instanceof Error ? err : new Error(String(err)); | |
| 22 | const reason = /jsx[-/]dev[-/]?runtime/i.test(e.message) | |
| 23 | ? "jsx-dev-runtime" | |
| 24 | : "other"; | |
| 25 | return { ok: false, reason, err: e }; | |
| 26 | } | |
| 27 | } | |
| 28 | ||
| 29 | const repo = (name: string, score: number, grade = "?") => ({ | |
| 30 | repo: { name, description: null }, | |
| 31 | healthScore: score, | |
| 32 | healthGrade: grade, | |
| 33 | }); | |
| 34 | ||
| 35 | describe("pickRepoCoachPicks — pure helper", () => { | |
| 36 | it("filters out healthy repos (score >= 90)", async () => { | |
| 37 | const loaded = await tryLoad(); | |
| 38 | if (!loaded.ok) { | |
| 39 | expect(loaded.reason).toBe("jsx-dev-runtime"); | |
| 40 | return; | |
| 41 | } | |
| 42 | const fn = loaded.pickRepoCoachPicks; | |
| 43 | const picks = fn([repo("a", 92), repo("b", 85), repo("c", 95)]); | |
| 44 | expect(picks.map((p: any) => p.repo.name)).toEqual(["b"]); | |
| 45 | }); | |
| 46 | ||
| 47 | it("filters out unscored repos (score === 0)", async () => { | |
| 48 | const loaded = await tryLoad(); | |
| 49 | if (!loaded.ok) { | |
| 50 | expect(loaded.reason).toBe("jsx-dev-runtime"); | |
| 51 | return; | |
| 52 | } | |
| 53 | const fn = loaded.pickRepoCoachPicks; | |
| 54 | const picks = fn([repo("a", 0), repo("b", 70), repo("c", 0)]); | |
| 55 | expect(picks.map((p: any) => p.repo.name)).toEqual(["b"]); | |
| 56 | }); | |
| 57 | ||
| 58 | it("returns the lowest-N scores in ascending order", async () => { | |
| 59 | const loaded = await tryLoad(); | |
| 60 | if (!loaded.ok) { | |
| 61 | expect(loaded.reason).toBe("jsx-dev-runtime"); | |
| 62 | return; | |
| 63 | } | |
| 64 | const fn = loaded.pickRepoCoachPicks; | |
| 65 | const picks = fn([ | |
| 66 | repo("a", 80), | |
| 67 | repo("b", 50), | |
| 68 | repo("c", 70), | |
| 69 | repo("d", 60), | |
| 70 | ]); | |
| 71 | expect(picks.map((p: any) => p.repo.name)).toEqual(["b", "d", "c"]); | |
| 72 | }); | |
| 73 | ||
| 74 | it("respects the topN cap (default 3)", async () => { | |
| 75 | const loaded = await tryLoad(); | |
| 76 | if (!loaded.ok) { | |
| 77 | expect(loaded.reason).toBe("jsx-dev-runtime"); | |
| 78 | return; | |
| 79 | } | |
| 80 | const fn = loaded.pickRepoCoachPicks; | |
| 81 | const all = [ | |
| 82 | repo("a", 10), | |
| 83 | repo("b", 20), | |
| 84 | repo("c", 30), | |
| 85 | repo("d", 40), | |
| 86 | repo("e", 50), | |
| 87 | ]; | |
| 88 | expect(fn(all).length).toBe(3); | |
| 89 | expect(fn(all, 5).length).toBe(5); | |
| 90 | expect(fn(all, 1)[0].repo.name).toBe("a"); | |
| 91 | }); | |
| 92 | ||
| 93 | it("returns [] when no repos qualify", async () => { | |
| 94 | const loaded = await tryLoad(); | |
| 95 | if (!loaded.ok) { | |
| 96 | expect(loaded.reason).toBe("jsx-dev-runtime"); | |
| 97 | return; | |
| 98 | } | |
| 99 | const fn = loaded.pickRepoCoachPicks; | |
| 100 | expect(fn([])).toEqual([]); | |
| 101 | expect(fn([repo("a", 0), repo("b", 95)])).toEqual([]); | |
| 102 | }); | |
| 103 | }); |