| 1 | import type { PullRequestCheck, PullRequestCheckStatus } from "@t3tools/contracts"; |
| 2 | import { describe, expect, it } from "vite-plus/test"; |
| 3 | |
| 4 | import { dedupeChecks } from "./pullRequestChecks.ts"; |
| 5 | |
| 6 | function entry( |
| 7 | name: string, |
| 8 | status: PullRequestCheckStatus, |
| 9 | extra: { readonly workflowName?: string | null; readonly at?: string | null } = {}, |
| 10 | ): { |
| 11 | readonly check: PullRequestCheck; |
| 12 | readonly workflowName: string | null; |
| 13 | readonly at: string | null; |
| 14 | } { |
| 15 | return { |
| 16 | check: { name, status, description: null, url: null }, |
| 17 | workflowName: extra.workflowName ?? null, |
| 18 | at: extra.at ?? null, |
| 19 | }; |
| 20 | } |
| 21 | |
| 22 | describe("dedupeChecks", () => { |
| 23 | it("keeps the newest run of a check the host listed twice", () => { |
| 24 | const checks = dedupeChecks([ |
| 25 | entry("Prepare PR size config", "success", { |
| 26 | workflowName: "PR Size", |
| 27 | at: "2026-08-11T16:06:25Z", |
| 28 | }), |
| 29 | entry("Prepare PR size config", "pending", { |
| 30 | workflowName: "PR Size", |
| 31 | at: "2026-08-11T17:01:04Z", |
| 32 | }), |
| 33 | ]); |
| 34 | |
| 35 | expect(checks.map((check) => [check.name, check.status])).toEqual([ |
| 36 | ["Prepare PR size config", "pending"], |
| 37 | ]); |
| 38 | }); |
| 39 | |
| 40 | it("holds a check at the place it first appeared, so a re-run does not reshuffle the list", () => { |
| 41 | const checks = dedupeChecks([ |
| 42 | entry("lint", "success", { workflowName: "CI", at: "2026-08-11T16:00:00Z" }), |
| 43 | entry("test", "success", { workflowName: "CI", at: "2026-08-11T16:00:00Z" }), |
| 44 | entry("lint", "failure", { workflowName: "CI", at: "2026-08-11T18:00:00Z" }), |
| 45 | ]); |
| 46 | |
| 47 | expect(checks.map((check) => [check.name, check.status])).toEqual([ |
| 48 | ["lint", "failure"], |
| 49 | ["test", "success"], |
| 50 | ]); |
| 51 | }); |
| 52 | |
| 53 | it("keeps distinct workflow and check pairs even when their names join to the same text", () => { |
| 54 | const checks = dedupeChecks([ |
| 55 | entry("Linux tests", "success", { |
| 56 | workflowName: "Build", |
| 57 | at: "2026-08-11T16:00:00Z", |
| 58 | }), |
| 59 | entry("tests", "success", { |
| 60 | workflowName: "Build Linux", |
| 61 | at: "2026-08-11T17:00:00Z", |
| 62 | }), |
| 63 | entry("Linux tests", "failure", { |
| 64 | workflowName: "Build", |
| 65 | at: "2026-08-11T18:00:00Z", |
| 66 | }), |
| 67 | ]); |
| 68 | |
| 69 | expect(checks.map((check) => [check.name, check.status])).toEqual([ |
| 70 | ["Linux tests", "failure"], |
| 71 | ["tests", "success"], |
| 72 | ]); |
| 73 | }); |
| 74 | |
| 75 | it("loses a run that never said when it happened to one that did, whichever came first", () => { |
| 76 | const undated = dedupeChecks([ |
| 77 | entry("build", "success", { at: "2026-08-11T16:00:00Z" }), |
| 78 | entry("build", "pending"), |
| 79 | ]); |
| 80 | const dated = dedupeChecks([ |
| 81 | entry("build", "pending"), |
| 82 | entry("build", "success", { at: "2026-08-11T16:00:00Z" }), |
| 83 | ]); |
| 84 | |
| 85 | expect([undated[0]?.status, dated[0]?.status]).toEqual(["success", "success"]); |
| 86 | }); |
| 87 | |
| 88 | it("takes the last copy when neither run is dated, which is how an update is listed", () => { |
| 89 | const checks = dedupeChecks([entry("build", "pending"), entry("build", "failure")]); |
| 90 | |
| 91 | expect(checks.map((check) => check.status)).toEqual(["failure"]); |
| 92 | }); |
| 93 | |
| 94 | it("keeps two workflows that name a job the same thing, and says which is which", () => { |
| 95 | const checks = dedupeChecks([ |
| 96 | entry("build", "success", { workflowName: "CI", at: "2026-08-11T16:00:00Z" }), |
| 97 | entry("build", "failure", { workflowName: "Release", at: "2026-08-11T16:00:00Z" }), |
| 98 | ]); |
| 99 | |
| 100 | expect(checks.map((check) => [check.name, check.status])).toEqual([ |
| 101 | ["CI / build", "success"], |
| 102 | ["Release / build", "failure"], |
| 103 | ]); |
| 104 | }); |
| 105 | |
| 106 | it("leaves a colliding check with no workflow of its own unqualified", () => { |
| 107 | // An app-provided check run belongs to no workflow, which GitHub reports as an empty name. |
| 108 | const checks = dedupeChecks([ |
| 109 | entry("build", "success", { workflowName: "", at: "2026-08-11T16:00:00Z" }), |
| 110 | entry("build", "failure", { workflowName: "CI", at: "2026-08-11T16:00:00Z" }), |
| 111 | ]); |
| 112 | |
| 113 | expect(checks.map((check) => check.name)).toEqual(["build", "CI / build"]); |
| 114 | }); |
| 115 | }); |