1import { describe, expect, it } from "vite-plus/test";
2
3import {
4 buildCollapsedProposedPlanPreviewMarkdown,
5 buildPlanImplementationThreadTitle,
6 buildPlanImplementationPrompt,
7 buildProposedPlanMarkdownFilename,
8 resolvePlanFollowUpSubmission,
9} from "./proposedPlan";
10
11describe("buildPlanImplementationPrompt", () => {
12 it("formats the plan exactly like the Codex follow-up handoff prompt", () => {
13 expect(buildPlanImplementationPrompt("## Ship it\n\n- step 1\n")).toBe(
14 "PLEASE IMPLEMENT THIS PLAN:\n## Ship it\n\n- step 1",
15 );
16 });
17});
18
19describe("buildCollapsedProposedPlanPreviewMarkdown", () => {
20 it("drops the redundant title heading and preserves the following markdown lines", () => {
21 expect(
22 buildCollapsedProposedPlanPreviewMarkdown(
23 "# Integrate RPC\n\n## Summary\n\n- step 1\n- step 2",
24 {
25 maxLines: 4,
26 },
27 ),
28 ).toBe("- step 1\n- step 2");
29 });
30
31 it("appends an overflow marker when the preview truncates remaining content", () => {
32 expect(
33 buildCollapsedProposedPlanPreviewMarkdown("# Integrate RPC\n\n- step 1\n- step 2\n- step 3", {
34 maxLines: 2,
35 }),
36 ).toBe("- step 1\n- step 2\n\n...");
37 });
38});
39
40describe("resolvePlanFollowUpSubmission", () => {
41 it.each(["", "Consider this "])(
42 "keeps context-bearing feedback in plan mode with prose %j",
43 (prose) => {
44 const draftText = `${prose}[PR #42](t3-context://v1/review-comment/pr-42)`;
45 expect(resolvePlanFollowUpSubmission({ draftText, planMarkdown: "# Plan" })).toEqual({
46 text: draftText,
47 interactionMode: "plan",
48 });
49 },
50 );
51 it("switches to default mode when implementing the ready plan without extra text", () => {
52 expect(
53 resolvePlanFollowUpSubmission({
54 draftText: " ",
55 planMarkdown: "## Ship it\n\n- step 1\n",
56 }),
57 ).toEqual({
58 text: "PLEASE IMPLEMENT THIS PLAN:\n## Ship it\n\n- step 1",
59 interactionMode: "default",
60 });
61 });
62
63 it("stays in plan mode when the user adds a follow-up prompt", () => {
64 expect(
65 resolvePlanFollowUpSubmission({
66 draftText: "Refine step 2 first",
67 planMarkdown: "## Ship it\n\n- step 1\n",
68 }),
69 ).toEqual({
70 text: "Refine step 2 first",
71 interactionMode: "plan",
72 });
73 });
74});
75
76describe("buildPlanImplementationThreadTitle", () => {
77 it("uses the plan heading when building the implementation thread title", () => {
78 expect(buildPlanImplementationThreadTitle("# Integrate RPC\n\nBody")).toBe(
79 "Implement Integrate RPC",
80 );
81 });
82
83 it("falls back when the plan has no markdown heading", () => {
84 expect(buildPlanImplementationThreadTitle("- step 1")).toBe("Implement plan");
85 });
86});
87
88describe("buildProposedPlanMarkdownFilename", () => {
89 it("derives a stable markdown filename from the plan heading", () => {
90 expect(buildProposedPlanMarkdownFilename("# Integrate Effect RPC Into Server App")).toBe(
91 "integrate-effect-rpc-into-server-app.md",
92 );
93 });
94
95 it("falls back to a generic filename when the plan has no heading", () => {
96 expect(buildProposedPlanMarkdownFilename("- step 1")).toBe("plan.md");
97 });
98});