1import type { PullRequestActivity, PullRequestCheck, PullRequestComment } from "@t3tools/contracts";
2import { describe, expect, it } from "vite-plus/test";
3import { pullRequestChecksSummary, pullRequestReviewSummary } from "./pullRequestStatus";
4
5const author = { login: "julius", name: null, avatarUrl: null };
6function review(state: string, at: string): PullRequestComment {
7 return {
8 id: `${state}:${at}`,
9 kind: "review",
10 author,
11 body: "",
12 createdAt: at,
13 url: null,
14 path: null,
15 reviewState: state,
16 };
17}
18function activity(
19 comments: readonly PullRequestComment[],
20): Pick<PullRequestActivity, "comments" | "commits"> {
21 return { comments, commits: [] };
22}
23function check(status: PullRequestCheck["status"]): PullRequestCheck {
24 return { name: status, status, url: null, description: null };
25}
26
27describe("mobile overview review status", () => {
28 it("uses each reviewer's latest verdict even when history arrives out of order", () => {
29 const result = pullRequestReviewSummary(
30 { reviewers: [] },
31 activity([
32 review("CHANGES_REQUESTED", "2026-10-10T10:00:00Z"),
33 review("APPROVED", "2026-10-10T09:00:00Z"),
34 ]),
35 );
36 expect(result.title).toBe("Changes requested");
37 expect(result.reviews).toHaveLength(1);
38 });
39
40 it("does not claim a dismissed approval or an approval preceding the latest commit", () => {
41 const approved = review("APPROVED", "2026-10-10T09:00:00Z");
42 expect(
43 pullRequestReviewSummary(
44 { reviewers: [] },
45 activity([approved, review("DISMISSED", "2026-10-10T10:00:00Z")]),
46 ).reviews,
47 ).toEqual([]);
48 const result = pullRequestReviewSummary(
49 { reviewers: [author] },
50 {
51 comments: [approved],
52 commits: [
53 { oid: "abc123", messageHeadline: "Update", committedDate: "2026-10-10T10:00:00Z" },
54 ],
55 },
56 );
57 expect(result.title).toBe("Awaiting review");
58 });
59
60 it("keeps an approval when a later review only comments, and normalizes provider spelling", () => {
61 const result = pullRequestReviewSummary(
62 { reviewers: [] },
63 activity([
64 review("approved", "2026-10-10T09:00:00Z"),
65 review("COMMENTED", "2026-10-10T10:00:00Z"),
66 ]),
67 );
68 expect(result.title).toBe("Approved by julius");
69 expect(result.reviews).toHaveLength(1);
70 expect(
71 pullRequestReviewSummary(
72 { reviewers: [] },
73 activity([review("changes-requested", "2026-10-10T11:00:00Z")]),
74 ).title,
75 ).toBe("Changes requested");
76 });
77
78 it("includes comment-only reviewers once without treating their comments as approval", () => {
79 const result = pullRequestReviewSummary(
80 { reviewers: [] },
81 activity([
82 review("COMMENTED", "2026-10-10T09:00:00Z"),
83 review("commented", "2026-10-10T10:00:00Z"),
84 ]),
85 );
86 expect(result.title).toBe("Reviews");
87 expect(result.reviews).toEqual([
88 { ...review("commented", "2026-10-10T10:00:00Z"), reviewState: "COMMENTED" },
89 ]);
90 });
91});
92
93describe("mobile overview check status", () => {
94 it("only says all passed when every check succeeded", () => {
95 expect(pullRequestChecksSummary({ checks: [check("success"), check("success")] }).title).toBe(
96 "All checks passed",
97 );
98 expect(pullRequestChecksSummary({ checks: [check("success"), check("skipped")] }).title).toBe(
99 "Checks completed",
100 );
101 expect(pullRequestChecksSummary({ checks: [] }).title).toBe("No checks reported");
102 });
103
104 it("prioritizes failed checks while others are running", () => {
105 expect(
106 pullRequestChecksSummary({ checks: [check("success"), check("pending"), check("failure")] }),
107 ).toMatchObject({ title: "1 check failing", count: "1 of 3" });
108 });
109});