Spaces:
Sleeping
Sleeping
| /** | |
| * buildFailureHandler.test.ts — Build Failure Handler (S40) | |
| * 14 test: action mapping, priority, targetFiles, instructions, DI, guards | |
| */ | |
| import { describe, it, expect, beforeEach } from "vitest"; | |
| import { | |
| handleBuildFailure, | |
| shouldUseCriticMode, | |
| extractTargetFiles, | |
| _setTestHandler, | |
| _resetHandler, | |
| } from "@/lib/buildFailureHandler"; | |
| beforeEach(() => _resetHandler()); | |
| // ── handleBuildFailure ──────────────────────────────────────────────────── | |
| describe("handleBuildFailure", () => { | |
| it("1. errore triviale → action=patch, priority=low", () => { | |
| const d = handleBuildFailure("Unused variable 'x' at line 5."); | |
| expect(d.action).toBe("patch"); | |
| expect(d.priority).toBe("low"); | |
| }); | |
| it("2. errore serio → action ≠ patch o almeno priority >= medium", () => { | |
| const d = handleBuildFailure("Cannot find module '@/lib/missing'"); | |
| // action può essere patch/rewrite/split ma priority NON può essere low | |
| if (d.action === "patch") { | |
| expect(["medium", "high", "critical"]).toContain(d.priority); | |
| } else { | |
| expect(["rewrite", "split", "escalate"]).toContain(d.action); | |
| } | |
| }); | |
| it("3. retryCount >= 3 → action=escalate, priority=critical", () => { | |
| const d = handleBuildFailure("Cannot find module '@/missing'", { retryCount: 3 }); | |
| expect(d.action).toBe("escalate"); | |
| expect(d.priority).toBe("critical"); | |
| }); | |
| it("4. action=split → priority=high", () => { | |
| // Forza split_task via DI | |
| _setTestHandler({ | |
| classify: () => "serious", | |
| analyze: () => ({ | |
| scope: "systemic", strategy: "split_task", confidence: 0.6, | |
| reason: "Too many retries", affectedFiles: [], | |
| suggestedAction: "split it", escalate: false, | |
| }), | |
| }); | |
| const d = handleBuildFailure("any error", { retryCount: 2 }); | |
| expect(d.priority).toBe("high"); | |
| }); | |
| it("5. instructions è stringa non vuota", () => { | |
| const d = handleBuildFailure("Build error occurred"); | |
| expect(typeof d.instructions).toBe("string"); | |
| expect(d.instructions.length).toBeGreaterThan(10); | |
| }); | |
| it("6. instructions contiene [PATCH] per azione patch", () => { | |
| _setTestHandler({ | |
| classify: () => "trivial", | |
| analyze: () => ({ | |
| scope: "local", strategy: "patch", confidence: 0.9, | |
| reason: "trivial", affectedFiles: ["src/foo.ts"], | |
| suggestedAction: "fix it", escalate: false, | |
| }), | |
| }); | |
| const d = handleBuildFailure("Unused variable"); | |
| expect(d.instructions).toContain("[PATCH]"); | |
| }); | |
| it("7. instructions contiene [ESCALATE] per action=escalate", () => { | |
| const d = handleBuildFailure("Cannot find module '@/lib/missing'", { retryCount: 4 }); | |
| expect(d.instructions).toContain("[ESCALATE]"); | |
| }); | |
| it("8. targetFiles è array (anche vuoto)", () => { | |
| const d = handleBuildFailure("Generic build error"); | |
| expect(Array.isArray(d.targetFiles)).toBe(true); | |
| }); | |
| it("9. targetFiles include i file se l'errore li contiene", () => { | |
| const d = handleBuildFailure( | |
| "Error in src/lib/taskClassifier.ts: Cannot find module", | |
| ); | |
| expect(d.targetFiles.some(f => f.includes("taskClassifier.ts"))).toBe(true); | |
| }); | |
| it("10. usesCriticMode=true per errore serio", () => { | |
| const d = handleBuildFailure("Cannot find module '@/lib/planner'"); | |
| expect(d.usesCriticMode).toBe(true); | |
| }); | |
| it("10b. usesCriticMode=false per errore triviale + retryCount=0", () => { | |
| const d = handleBuildFailure("Unused variable 'x'."); | |
| expect(d.usesCriticMode).toBe(false); | |
| }); | |
| it("11. errorSummary è stringa ≤ 200 char", () => { | |
| const longErr = "E".repeat(500); | |
| const d = handleBuildFailure(longErr); | |
| expect(d.errorSummary.length).toBeLessThanOrEqual(200); | |
| }); | |
| it("12. tutti i campi obbligatori presenti", () => { | |
| const d = handleBuildFailure("Any error"); | |
| const keys: (keyof typeof d)[] = [ | |
| "action", "priority", "targetFiles", "instructions", "usesCriticMode", "errorSummary", | |
| ]; | |
| for (const k of keys) { | |
| expect(d).toHaveProperty(k); | |
| } | |
| }); | |
| }); | |
| // ── shouldUseCriticMode ─────────────────────────────────────────────────── | |
| describe("shouldUseCriticMode", () => { | |
| it("13. cannot find module → true", () => { | |
| expect(shouldUseCriticMode("Cannot find module '@/foo'")).toBe(true); | |
| }); | |
| it("13b. unused variable → false", () => { | |
| expect(shouldUseCriticMode("Unused variable 'y'.")).toBe(false); | |
| }); | |
| it("13c. retryCount=2 → true qualunque errore", () => { | |
| expect(shouldUseCriticMode("Minor warning", 2)).toBe(true); | |
| }); | |
| }); | |
| // ── extractTargetFiles ──────────────────────────────────────────────────── | |
| describe("extractTargetFiles", () => { | |
| it("14. estrae file da errore con path", () => { | |
| const files = extractTargetFiles("Error in src/core/agentLoop.ts line 42"); | |
| expect(files.some(f => f.includes("agentLoop.ts"))).toBe(true); | |
| }); | |
| it("14b. nessun path → array (anche vuoto, non crasha)", () => { | |
| const files = extractTargetFiles("Build failed."); | |
| expect(Array.isArray(files)).toBe(true); | |
| }); | |
| }); | |