Files
Rune-Spec/tests/agent/e2e-plan.test.ts

133 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
});
});