test: plan 阶段端到端测试(8 个用例)
This commit is contained in:
132
tests/agent/e2e-plan.test.ts
Normal file
132
tests/agent/e2e-plan.test.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from "bun:test";
|
||||
import { createRunner } from "./tier1-command.ts";
|
||||
import {
|
||||
setupTempDir,
|
||||
cleanupTempDir,
|
||||
getTempDir,
|
||||
createFreshProject,
|
||||
changeFileExists,
|
||||
} from "./fixtures.ts";
|
||||
import { assertDocCreated, assertDocContains, assertConfigInvalid } from "./validators.ts";
|
||||
import { scanChanges } from "../../src/core/scanner.ts";
|
||||
import type { RuneConfig } from "../../src/types.ts";
|
||||
|
||||
describe("e2e: plan 阶段", () => {
|
||||
let runner: ReturnType<typeof createRunner>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await setupTempDir();
|
||||
runner = createRunner();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await cleanupTempDir();
|
||||
});
|
||||
|
||||
it("单文档按模板生成在正确路径", async () => {
|
||||
const config = await createFreshProject();
|
||||
const result = await runner.runPlan(getTempDir(), "user-auth", "design", config);
|
||||
|
||||
expect(result.files).toContain("design.md");
|
||||
assertDocCreated(getTempDir(), "user-auth", "design");
|
||||
assertDocContains(getTempDir(), "user-auth", "design", "user-auth");
|
||||
});
|
||||
|
||||
it("多文档无依赖时均生成", async () => {
|
||||
const config = await createFreshProject();
|
||||
await runner.runPlan(getTempDir(), "my-change", "design", config);
|
||||
await runner.runPlan(getTempDir(), "my-change", "task", config);
|
||||
|
||||
expect(changeFileExists("my-change", "design.md")).toBe(true);
|
||||
expect(changeFileExists("my-change", "task.md")).toBe(true);
|
||||
|
||||
const changes = await scanChanges(getTempDir(), config);
|
||||
expect(changes).toHaveLength(1);
|
||||
expect(changes[0]!.planCompleted).toBe(true);
|
||||
expect(changes[0]!.buildUnlocked).toBe(true);
|
||||
});
|
||||
|
||||
it("模板变量 {{change-name}} 被替换", async () => {
|
||||
const config = await createFreshProject();
|
||||
await runner.runPlan(getTempDir(), "用户-login", "design", config);
|
||||
|
||||
assertDocContains(getTempDir(), "用户-login", "design", "用户-login 设计文档");
|
||||
});
|
||||
|
||||
it("使用自定义 plan 配置(单文档 spec)", async () => {
|
||||
const config: RuneConfig = {
|
||||
stages: {
|
||||
plan: {
|
||||
documents: [{ name: "spec", prompt: "生成规格", template: "# {{change-name}} 规格\n" }],
|
||||
},
|
||||
},
|
||||
};
|
||||
await createFreshProject(["opencode"]);
|
||||
const result = await runner.runPlan(getTempDir(), "my-feature", "spec", config);
|
||||
|
||||
expect(result.files).toContain("spec.md");
|
||||
assertDocContains(getTempDir(), "my-feature", "spec", "my-feature 规格");
|
||||
});
|
||||
|
||||
it("多文档有依赖时 planCompleted 全完成后才为 true", async () => {
|
||||
const config = await createFreshProject();
|
||||
|
||||
await runner.runPlan(getTempDir(), "dep-test", "design", config);
|
||||
|
||||
let changes = await scanChanges(getTempDir(), config);
|
||||
expect(changes[0]!.planCompleted).toBe(false);
|
||||
|
||||
await runner.runPlan(getTempDir(), "dep-test", "task", config);
|
||||
|
||||
changes = await scanChanges(getTempDir(), config);
|
||||
expect(changes[0]!.planCompleted).toBe(true);
|
||||
expect(changes[0]!.buildUnlocked).toBe(true);
|
||||
});
|
||||
|
||||
it("已有变更再次 plan 另一个文档(重复 plan)", async () => {
|
||||
const config: RuneConfig = {
|
||||
stages: {
|
||||
plan: {
|
||||
documents: [
|
||||
{ name: "design", prompt: "生成设计", template: "# 设计 #\n" },
|
||||
{ name: "task", prompt: "生成任务", template: "# 任务 #\n" },
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await runner.runPlan(getTempDir(), "multi", "design", config);
|
||||
assertDocCreated(getTempDir(), "multi", "design");
|
||||
|
||||
const result = await runner.runPlan(getTempDir(), "multi", "task", config);
|
||||
expect(result.files).toContain("task.md");
|
||||
|
||||
const changes = await scanChanges(getTempDir(), config);
|
||||
expect(changes[0]!.planCompleted).toBe(true);
|
||||
});
|
||||
|
||||
it("循环依赖配置被校验拒绝", () => {
|
||||
const config: RuneConfig = {
|
||||
stages: {
|
||||
plan: {
|
||||
documents: [
|
||||
{ name: "a", prompt: "a", depend: ["b"] },
|
||||
{ name: "b", prompt: "b", depend: ["a"] },
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
assertConfigInvalid(config);
|
||||
});
|
||||
|
||||
it("自依赖配置被校验拒绝", () => {
|
||||
const config: RuneConfig = {
|
||||
stages: {
|
||||
plan: {
|
||||
documents: [{ name: "design", prompt: "设计", depend: ["design"] }],
|
||||
},
|
||||
},
|
||||
};
|
||||
assertConfigInvalid(config);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user