import { describe, expect, it } from "vite-plus/test";
import {
countReviewCommentContexts,
formatReviewCommentContext,
parseReviewCommentMessageSegments,
parseReviewInlineComments,
type ReviewCommentTarget,
} from "./reviewCommentSelection";
function makeTarget(): ReviewCommentTarget {
return {
sectionId: "section-1",
sectionTitle: "Working tree",
filePath: "apps/demo/src/main.ts",
startIndex: 0,
endIndex: 1,
lines: [
{
kind: "line",
id: "line-1",
change: "delete",
oldLineNumber: 7,
newLineNumber: null,
content: "const retryLimit = 2;",
additionTokenIndex: null,
deletionTokenIndex: 0,
comparison: null,
},
{
kind: "line",
id: "line-2",
change: "add",
oldLineNumber: null,
newLineNumber: 7,
content: "const retryLimit = 4;",
additionTokenIndex: 0,
deletionTokenIndex: null,
comparison: null,
},
],
};
}
describe("review comment serialization", () => {
it("preserves enough metadata for inline diff rendering", () => {
const serialized = formatReviewCommentContext(makeTarget(), "Please keep this configurable.");
expect(countReviewCommentContexts(serialized)).toBe(1);
expect(parseReviewInlineComments(serialized)).toEqual([
expect.objectContaining({
sectionId: "section-1",
sectionTitle: "Working tree",
filePath: "apps/demo/src/main.ts",
startIndex: 0,
endIndex: 1,
text: "Please keep this configurable.",
diff: expect.stringContaining("-const retryLimit = 2;"),
}),
]);
});
it("splits chat text into review comment segments", () => {
const serialized = `Before\n${formatReviewCommentContext(makeTarget(), "Please keep this configurable.")}\nAfter`;
const segments = parseReviewCommentMessageSegments(serialized);
expect(segments).toHaveLength(3);
expect(segments[0]).toEqual(expect.objectContaining({ kind: "text", text: "Before\n" }));
expect(segments[1]).toEqual(
expect.objectContaining({
kind: "review-comment",
comment: expect.objectContaining({
filePath: "apps/demo/src/main.ts",
text: "Please keep this configurable.",
diff: expect.stringContaining("+const retryLimit = 4;"),
}),
}),
);
expect(segments[2]).toEqual(expect.objectContaining({ kind: "text", text: "\nAfter" }));
});
it("parses source-language review comments created by the web file viewer", () => {
const [segment] = parseReviewCommentMessageSegments(
[
'',
"Clarify this.",
"```md",
"# Plan",
"- Step one",
"```",
"",
].join("\n"),
);
expect(segment).toEqual(
expect.objectContaining({
kind: "review-comment",
comment: expect.objectContaining({
filePath: "docs/plan.md",
fenceLanguage: "md",
diff: "# Plan\n- Step one",
}),
}),
);
});
it("keeps fenced examples in comment prose separate from the context fence", () => {
const [segment] = parseReviewCommentMessageSegments(
[
'',
"Try this:",
"```ts",
"const value = 1;",
"```",
"Then retry.",
"```diff",
"@@ -0,0 +1,1 @@",
"+one",
"```",
"",
].join("\n"),
);
expect(segment).toEqual(
expect.objectContaining({
kind: "review-comment",
comment: expect.objectContaining({
text: ["Try this:", "```ts", "const value = 1;", "```", "Then retry."].join("\n"),
diff: "@@ -0,0 +1,1 @@\n+one",
}),
}),
);
});
it("round-trips greater-than signs in review attributes", () => {
const serialized = formatReviewCommentContext(
{ ...makeTarget(), sectionTitle: "Changes > 5" },
"Check this.",
);
const [comment] = parseReviewInlineComments(serialized);
expect(serialized).toContain('sectionTitle="Changes > 5"');
expect(comment?.sectionTitle).toBe("Changes > 5");
});
});