Skip to content
Source
Sign inSign up

pullRequestDiffComments.test.ts

132 lines4.1 KB

1import { describe, expect, it } from "vite-plus/test";
2import type { PullRequestReviewThread } from "@t3tools/contracts";
3import type { NativeReviewDiffData } from "../review/nativeReviewDiffAdapter";
4import { annotatePullRequestDiff, reviewPositionLabel } from "./pullRequestDiffComments";
5const data: NativeReviewDiffData = {
6 rows: [
7 { kind: "file", id: "header", fileId: "f", filePath: "a.ts" },
8 { kind: "line", id: "old", fileId: "f", change: "delete", oldLineNumber: 2 },
9 { kind: "line", id: "new", fileId: "f", change: "add", newLineNumber: 2 },
10 ],
11 files: [{ id: "f", path: "a.ts", language: "typescript", additions: 1, deletions: 1 }],
12 commentTargetsByRowId: new Map(),
13 rowIdByCommentLineId: new Map(),
14 additions: 1,
15 deletions: 1,
16};
17const thread: PullRequestReviewThread = {
18 id: "t",
19 path: "a.ts",
20 line: 2,
21 side: "left",
22 isResolved: false,
23 isOutdated: false,
24 comments: [],
25};
26describe("PR comments in continuous native diffs", () => {
27 it("returns unannotated data unchanged without reading or indexing rows", () => {
28 const unannotated = {
29 ...data,
30 get rows(): NativeReviewDiffData["rows"] {
31 throw new Error("Empty annotation must not read rows");
32 },
33 };
34 expect(annotatePullRequestDiff(unannotated, [], [], undefined)).toBe(unannotated);
35 expect(annotatePullRequestDiff(data, [], [], undefined).rows).toBe(data.rows);
36 });
37​
38 it("anchors old/new lines separately despite identical line numbers", () => {
39 const annotated = annotatePullRequestDiff(
40 data,
41 [thread, { ...thread, id: "right", side: "right" }],
42 [],
43 "abc",
44 );
45 expect(annotated.rows.map((row) => row.id)).toEqual([
46 "header",
47 "old",
48 "discussion:t",
49 "new",
50 "discussion:right",
51 ]);
52 });
53 it("keeps outdated and unloaded anchors off the current code", () => {
54 const annotated = annotatePullRequestDiff(
55 data,
56 [
57 { ...thread, isOutdated: true },
58 { ...thread, id: "missing", path: "b.ts" },
59 ],
60 [
61 {
62 id: "draft",
63 path: "a.ts",
64 position: { kind: "added", newLine: 2 },
65 body: "Feedback",
66 code: "",
67 headSha: "old",
68 },
69 ],
70 "new",
71 );
72 expect(annotated.rows).toEqual(data.rows);
73 });
74 it("supports file-level threads and current private drafts without changing code IDs", () => {
75 const annotated = annotatePullRequestDiff(
76 data,
77 [{ ...thread, line: null }],
78 [
79 {
80 id: "draft",
81 path: "a.ts",
82 position: { kind: "added", newLine: 2 },
83 body: "Feedback",
84 code: "",
85 headSha: "abc",
86 },
87 ],
88 "abc",
89 );
90 expect(annotated.rows.map((row) => row.id)).toEqual([
91 "header",
92 "discussion:t",
93 "old",
94 "new",
95 "draft:draft",
96 ]);
97 expect(annotated.commentTargetsByRowId).toBe(data.commentTargetsByRowId);
98 });
99 it("counts a single-comment discussion in the singular", () => {
100 const annotated = annotatePullRequestDiff(
101 data,
102 [
103 { ...thread, commentCount: 1 },
104 { ...thread, id: "right", side: "right", commentCount: 2 },
105 ],
106 [],
107 "abc",
108 );
109 expect(
110 annotated.rows
111 .filter((row) => row.kind === "comment")
112 .map((row) => row.commentText?.split("\n").at(-1)),
113 ).toEqual(["1 comment · Tap to open", "2 comments · Tap to open"]);
114 });
115 it("uses the old line number for left-side context when the line numbers differ", () => {
116 const position = { kind: "context" as const, side: "left" as const, oldLine: 7, newLine: 8 };
117 const annotated = annotatePullRequestDiff(
118 {
119 ...data,
120 rows: [
121 ...data.rows,
122 { kind: "line", id: "context", fileId: "f", oldLineNumber: 7, newLineNumber: 8 },
123 ],
124 },
125 [],
126 [{ id: "left", path: "a.ts", position, headSha: "abc", code: "", body: "Feedback" }],
127 "abc",
128 );
129 expect(annotated.rows.at(-1)?.id).toBe("draft:left");
130 expect(reviewPositionLabel(position)).toBe("Old line 7");
131 });
132});