232 lines
7.9 KiB
JavaScript
232 lines
7.9 KiB
JavaScript
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:");
|
|
});
|
|
});
|