import { describe, it, expect } from "vitest"; import { buildBasePrompt } from "../../src/prompts/base.js"; describe("buildBasePrompt", () => { // --- Basic output contract --- it("returns a non-empty string when called with no arguments", () => { const result = buildBasePrompt(); expect(typeof result).toBe("string"); expect(result.length).toBeGreaterThan(0); }); it("returns a non-empty string when called with an empty object", () => { const result = buildBasePrompt({}); expect(typeof result).toBe("string"); expect(result.length).toBeGreaterThan(0); }); it("is idempotent — same output on repeated calls with no input", () => { const a = buildBasePrompt(); const b = buildBasePrompt(); expect(a).toBe(b); }); // --- Role concepts --- it("mentions ChatGPT as a second-opinion assistant for Claude Code", () => { const prompt = buildBasePrompt(); expect(prompt).toContain("second-opinion"); expect(prompt).toContain("Claude Code"); }); it("states ChatGPT should not modify files", () => { const prompt = buildBasePrompt(); expect(prompt).toContain("files"); }); it("contains the concept of not running commands", () => { const prompt = buildBasePrompt(); expect(prompt).toMatch(/commands?\s*(?:,|\.)/); }); it("contains the concept of not deploying", () => { const prompt = buildBasePrompt(); expect(prompt).toContain("deploying"); }); it("contains the concept of not making autonomous decisions", () => { const prompt = buildBasePrompt(); expect(prompt).toContain("decisions"); }); // --- Reviewer / planner / debugger / architecture advisor / risk checker concepts --- it("includes reviewer role (review plans or code)", () => { const prompt = buildBasePrompt(); expect(prompt.toLowerCase()).toContain("review"); expect(prompt.toLowerCase()).toContain("code"); }); it("includes debugger role (debug issues)", () => { const prompt = buildBasePrompt(); expect(prompt).toMatch(/debug\s+issues?/i); }); it("includes architecture advisor role (analyse architecture)", () => { const prompt = buildBasePrompt(); expect(prompt).toContain("architecture"); }); it("includes risk checker role (identify risks)", () => { const prompt = buildBasePrompt(); expect(prompt).toMatch(/risks?/); }); // --- Project preferences --- it("reflects preference for simple architecture", () => { const prompt = buildBasePrompt(); expect(prompt).toContain("simple"); expect(prompt).toContain("architecture"); }); it("reflects preference for small changes", () => { const prompt = buildBasePrompt(); expect(prompt).toMatch(/small/i); }); it("reflects local-first approach (prefer local options)", () => { const prompt = buildBasePrompt(); expect(prompt).toContain("local"); }); it("reflects security-conscious stance (do not request secrets)", () => { const prompt = buildBasePrompt(); expect(prompt).toContain("secrets"); }); // --- "Your task" section gating --- it("does NOT emit 'Your task' section when question is absent", () => { const result = buildBasePrompt({ context: "some context" }); expect(result).not.toContain("Your task"); }); it("does NOT emit 'Your task' section when question is an empty string", () => { const result = buildBasePrompt({ question: "" }); expect(result).not.toContain("Your task"); }); it("emits 'Your task' section when question is present and non-empty", () => { const result = buildBasePrompt({ question: "How should I handle auth?" }); expect(result).toContain("Your task"); }); it("emits 'Your task' only when question is provided, ignoring other fields alone", () => { const result = buildBasePrompt({ context: "some context", constraints: ["must be safe"], projectSummary: "a project", taskSummary: "a task", }); expect(result).not.toContain("Your task"); }); // --- Input fields appended correctly (requires question) --- it("appends Question when question is provided", () => { const result = buildBasePrompt({ question: "What should I do?" }); expect(result).toContain("Question: What should I do?"); }); it("appends Context when context is provided alongside question", () => { const result = buildBasePrompt({ question: "Is this OK?", context: "This is the relevant code.", }); expect(result).toContain("Context: This is the relevant code."); }); it("does NOT append Context section when context is empty alongside question", () => { const result = buildBasePrompt({ question: "Is this OK?", context: "" }); expect(result).not.toContain("Context:"); }); it("appends Constraints list when constraints are provided alongside question", () => { const result = buildBasePrompt({ question: "Review my plan", constraints: ["must be safe", "must be fast"], }); expect(result).toContain("Constraints:"); expect(result).toContain("- must be safe"); expect(result).toContain("- must be fast"); }); it("does NOT append Constraints section when constraints array is empty", () => { const result = buildBasePrompt({ question: "Review my plan", constraints: [] }); expect(result).not.toContain("Constraints:"); }); it("appends Project summary when projectSummary is provided alongside question", () => { const result = buildBasePrompt({ question: "What should I do?", projectSummary: "A small Node.js API.", }); expect(result).toContain("Project summary: A small Node.js API."); }); it("does NOT append Project summary when projectSummary is empty", () => { const result = buildBasePrompt({ question: "What should I do?", projectSummary: "" }); expect(result).not.toContain("Project summary:"); }); it("appends Task summary when taskSummary is provided alongside question", () => { const result = buildBasePrompt({ question: "What should I do?", taskSummary: "Adding rate limiting.", }); expect(result).toContain("Task summary: Adding rate limiting."); }); it("does NOT append Task summary when taskSummary is empty", () => { const result = buildBasePrompt({ question: "What should I do?", taskSummary: "" }); expect(result).not.toContain("Task summary:"); }); // --- No tool-specific content --- it("does NOT contain tool-specific prompt identifiers", () => { const prompt = buildBasePrompt(); expect(prompt).not.toContain("review-plan"); expect(prompt).not.toContain("review_code"); expect(prompt).not.toContain("debug-issue"); expect(prompt).not.toContain("architecture-review"); }); // --- Full input test --- it("includes all sections when all fields are provided", () => { const result = buildBasePrompt({ question: "Is this approach correct?", context: "Current handler catches all errors.", constraints: ["no stack traces", "no raw data"], projectSummary: "Private VPC REST API.", taskSummary: "Adding rate limiting.", }); expect(result).toContain("Your task"); expect(result).toContain("Question: Is this approach correct?"); expect(result).toContain("Context: Current handler catches all errors."); expect(result).toContain("Constraints:"); expect(result).toContain("- no stack traces"); expect(result).toContain("- no raw data"); expect(result).toContain("Project summary: Private VPC REST API."); expect(result).toContain("Task summary: Adding rate limiting."); }); it("returns the base prompt (without task section) when question is undefined but other fields exist", () => { const result = buildBasePrompt({ context: "some context", constraints: ["rule 1"], projectSummary: "a summary", taskSummary: "a task", }); expect(result).not.toContain("Your task"); expect(result).not.toContain("Question:"); expect(result).not.toContain("Context: some context"); expect(result).not.toContain("Constraints:"); }); });