diff --git a/tests/agent/e2e-build.test.ts b/tests/agent/e2e-build.test.ts new file mode 100644 index 0000000..c515a4e --- /dev/null +++ b/tests/agent/e2e-build.test.ts @@ -0,0 +1,96 @@ +import { describe, it, expect, beforeEach, afterEach } from "bun:test"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import { createRunner } from "./tier1-command.ts"; +import { + setupTempDir, + cleanupTempDir, + getTempDir, + createFreshProject, + writeDoc, +} from "./fixtures.ts"; +import { scanChanges } from "../../src/core/scanner.ts"; +import { getChangeDir } from "../../src/core/config.ts"; + +describe("e2e: build 阶段", () => { + let runner: ReturnType; + + beforeEach(async () => { + await setupTempDir(); + runner = createRunner(); + }); + + afterEach(async () => { + await cleanupTempDir(); + }); + + it("单任务执行,勾选并产出文件", async () => { + const config = await createFreshProject(); + await writeDoc("auth", "task", "- [ ] 实现登录 API\n"); + + const result = await runner.runBuild(getTempDir(), "auth", config); + + expect(result.files).toContain("task.md"); + expect(result.files.length).toBeGreaterThanOrEqual(2); + + const tasks = await scanChanges(getTempDir(), config); + expect(tasks[0].taskProgress).toEqual({ completed: 1, total: 1 }); + }); + + it("多任务按顺序逐个勾选", async () => { + const config = await createFreshProject(); + await writeDoc("multi-task", "task", `- [ ] 任务A\n- [ ] 任务B\n- [ ] 任务C\n`); + + const result = await runner.runBuild(getTempDir(), "multi-task", config); + + expect(result.files).toHaveLength(4); + expect(result.files).toContain("task.md"); + + const taskContent = readFileSync( + join(getChangeDir(getTempDir(), "multi-task"), "task.md"), + "utf-8", + ); + expect(taskContent).toContain("- [x] 任务A"); + expect(taskContent).toContain("- [x] 任务B"); + expect(taskContent).toContain("- [x] 任务C"); + + const tasks = await scanChanges(getTempDir(), config); + expect(tasks[0].taskProgress).toEqual({ completed: 3, total: 3 }); + }); + + it("空 task 清单时 taskProgress 提示无任务", async () => { + const config = await createFreshProject(); + await writeDoc("empty", "task", "\n"); + + const changes = await scanChanges(getTempDir(), config); + const emptyChange = changes.find((c) => c.name === "empty"); + expect(emptyChange).toBeDefined(); + if (emptyChange) { + expect(emptyChange.taskProgress).toEqual({ completed: 0, total: 0 }); + } + }); + + it("plan 未完成时 build 不可用", async () => { + const config = await createFreshProject(); + + await expect(runner.runBuild(getTempDir(), "no-task", config)).rejects.toThrow( + "task.md 不存在", + ); + }); + + it("任务全部完成后状态为已完成", async () => { + const config = await createFreshProject(); + await writeDoc("done", "task", "- [x] 已完成任务\n"); + + const result = await runner.runBuild(getTempDir(), "done", config); + + expect(result.files).toEqual([]); + + const tasks = await scanChanges(getTempDir(), config); + const doneChange = tasks.find((c) => c.name === "done"); + expect(doneChange).toBeDefined(); + if (doneChange) { + expect(doneChange.taskProgress).toEqual({ completed: 1, total: 1 }); + } + }); +});