import { describe, it, expect, beforeEach } from "vitest"; import { ContinuationPromptsService } from "./continuation-prompts.service"; import { ContinuationPromptContext, FailureDetail, ContinuationPrompt } from "./interfaces"; describe("ContinuationPromptsService", () => { let service: ContinuationPromptsService; let baseContext: ContinuationPromptContext; beforeEach(() => { service = new ContinuationPromptsService(); baseContext = { taskId: "task-1", originalTask: "Implement user authentication", attemptNumber: 1, maxAttempts: 3, failures: [], filesChanged: ["src/auth/auth.service.ts"], }; }); describe("generatePrompt", () => { it("should generate a prompt with system and user sections", () => { const context: ContinuationPromptContext = { ...baseContext, failures: [ { type: "test-failure", message: "Test failed: should authenticate user", details: "Expected 200, got 401", }, ], }; const prompt = service.generatePrompt(context); expect(prompt).toBeDefined(); expect(prompt.systemPrompt).toContain("CRITICAL RULES"); expect(prompt.userPrompt).toContain("Implement user authentication"); expect(prompt.userPrompt).toContain("Test failed"); expect(prompt.constraints).toBeInstanceOf(Array); expect(prompt.priority).toBe("high"); }); it("should include attempt number in prompt", () => { const context: ContinuationPromptContext = { ...baseContext, attemptNumber: 2, failures: [ { type: "build-error", message: "Type error in auth.service.ts", }, ], }; const prompt = service.generatePrompt(context); expect(prompt.userPrompt).toContain("attempt 2 of 3"); }); it("should escalate priority on final attempt", () => { const context: ContinuationPromptContext = { ...baseContext, attemptNumber: 3, maxAttempts: 3, failures: [ { type: "test-failure", message: "Tests still failing", }, ], }; const prompt = service.generatePrompt(context); expect(prompt.priority).toBe("critical"); expect(prompt.constraints).toContain( "This is your LAST attempt. Failure means manual intervention required." ); }); it("should handle multiple failure types", () => { const context: ContinuationPromptContext = { ...baseContext, failures: [ { type: "test-failure", message: "Auth test failed", }, { type: "build-error", message: "Type error", }, { type: "coverage", message: "Coverage below 85%", }, ], }; const prompt = service.generatePrompt(context); expect(prompt.userPrompt).toContain("Auth test failed"); expect(prompt.userPrompt).toContain("Type error"); expect(prompt.userPrompt).toContain("Coverage below 85%"); }); }); describe("generateTestFailurePrompt", () => { it("should format test failures with details", () => { const failures: FailureDetail[] = [ { type: "test-failure", message: "should authenticate user", details: "Expected 200, got 401", location: "auth.service.spec.ts:42", }, { type: "test-failure", message: "should reject invalid credentials", details: "AssertionError: expected false to be true", location: "auth.service.spec.ts:58", }, ]; const prompt = service.generateTestFailurePrompt(failures); expect(prompt).toContain("should authenticate user"); expect(prompt).toContain("Expected 200, got 401"); expect(prompt).toContain("auth.service.spec.ts:42"); expect(prompt).toContain("should reject invalid credentials"); expect(prompt).toContain("Fix the implementation"); }); it("should include guidance for fixing tests", () => { const failures: FailureDetail[] = [ { type: "test-failure", message: "Test failed", }, ]; const prompt = service.generateTestFailurePrompt(failures); expect(prompt).toContain("Read the test"); expect(prompt).toContain("Fix the implementation"); expect(prompt).toContain("Run the test"); }); }); describe("generateBuildErrorPrompt", () => { it("should format build errors with location", () => { const failures: FailureDetail[] = [ { type: "build-error", message: "Type 'string' is not assignable to type 'number'", location: "auth.service.ts:25", }, { type: "build-error", message: "Cannot find name 'User'", location: "auth.service.ts:42", suggestion: "Import User from '@/entities'", }, ]; const prompt = service.generateBuildErrorPrompt(failures); expect(prompt).toContain("Type 'string' is not assignable"); expect(prompt).toContain("auth.service.ts:25"); expect(prompt).toContain("Cannot find name 'User'"); expect(prompt).toContain("Import User from"); }); it("should include build-specific guidance", () => { const failures: FailureDetail[] = [ { type: "build-error", message: "Syntax error", }, ]; const prompt = service.generateBuildErrorPrompt(failures); expect(prompt).toContain("TypeScript"); expect(prompt).toContain("Do not proceed until build passes"); }); }); describe("generateCoveragePrompt", () => { it("should show coverage gap", () => { const prompt = service.generateCoveragePrompt(72, 85); expect(prompt).toContain("72%"); expect(prompt).toContain("85%"); expect(prompt).toContain("13%"); // gap }); it("should provide guidance for improving coverage", () => { const prompt = service.generateCoveragePrompt(80, 85); expect(prompt).toContain("uncovered code paths"); expect(prompt).toContain("edge cases"); expect(prompt).toContain("error handling"); }); }); describe("generateIncompleteWorkPrompt", () => { it("should list incomplete work items", () => { const issues = [ "TODO: Implement password hashing", "FIXME: Add error handling", "Missing validation for email format", ]; const prompt = service.generateIncompleteWorkPrompt(issues); expect(prompt).toContain("TODO: Implement password hashing"); expect(prompt).toContain("FIXME: Add error handling"); expect(prompt).toContain("Missing validation"); }); it("should emphasize completion requirement", () => { const issues = ["Missing feature X"]; const prompt = service.generateIncompleteWorkPrompt(issues); expect(prompt).toContain("MUST complete ALL aspects"); expect(prompt).toContain("Do not leave TODO"); }); }); describe("getConstraints", () => { it("should return basic constraints for first attempt", () => { const constraints = service.getConstraints(1, 3); expect(constraints).toBeInstanceOf(Array); expect(constraints.length).toBeGreaterThan(0); }); it("should escalate constraints on second attempt", () => { const constraints = service.getConstraints(2, 3); expect(constraints).toContain("Focus only on failures, no new features"); }); it("should add strict constraints on third attempt", () => { const constraints = service.getConstraints(3, 3); expect(constraints).toContain("Minimal changes only, fix exact issues"); }); it("should add final warning on last attempt", () => { const constraints = service.getConstraints(3, 3); expect(constraints).toContain( "This is your LAST attempt. Failure means manual intervention required." ); }); it("should handle different max attempts", () => { const constraints = service.getConstraints(5, 5); expect(constraints).toContain( "This is your LAST attempt. Failure means manual intervention required." ); }); }); describe("formatFailuresForPrompt", () => { it("should format failures with all details", () => { const failures: FailureDetail[] = [ { type: "test-failure", message: "Test failed", details: "Expected true, got false", location: "file.spec.ts:10", suggestion: "Check the implementation", }, ]; const formatted = service.formatFailuresForPrompt(failures); expect(formatted).toContain("test-failure"); expect(formatted).toContain("Test failed"); expect(formatted).toContain("Expected true, got false"); expect(formatted).toContain("file.spec.ts:10"); expect(formatted).toContain("Check the implementation"); }); it("should handle failures without optional fields", () => { const failures: FailureDetail[] = [ { type: "lint-error", message: "Unused variable", }, ]; const formatted = service.formatFailuresForPrompt(failures); expect(formatted).toContain("lint-error"); expect(formatted).toContain("Unused variable"); }); it("should format multiple failures", () => { const failures: FailureDetail[] = [ { type: "test-failure", message: "Test 1 failed", }, { type: "build-error", message: "Build error", }, { type: "coverage", message: "Low coverage", }, ]; const formatted = service.formatFailuresForPrompt(failures); expect(formatted).toContain("Test 1 failed"); expect(formatted).toContain("Build error"); expect(formatted).toContain("Low coverage"); }); it("should handle empty failures array", () => { const failures: FailureDetail[] = []; const formatted = service.formatFailuresForPrompt(failures); expect(formatted).toBe(""); }); }); describe("priority assignment", () => { it("should set normal priority for first attempt with minor issues", () => { const context: ContinuationPromptContext = { ...baseContext, attemptNumber: 1, failures: [ { type: "lint-error", message: "Minor lint issue", }, ], }; const prompt = service.generatePrompt(context); expect(prompt.priority).toBe("normal"); }); it("should set high priority for build errors", () => { const context: ContinuationPromptContext = { ...baseContext, failures: [ { type: "build-error", message: "Build failed", }, ], }; const prompt = service.generatePrompt(context); expect(prompt.priority).toBe("high"); }); it("should set high priority for test failures", () => { const context: ContinuationPromptContext = { ...baseContext, failures: [ { type: "test-failure", message: "Test failed", }, ], }; const prompt = service.generatePrompt(context); expect(prompt.priority).toBe("high"); }); }); });