feat: 第二期 — Tier 2 场景级 mock + 错误/流程/依赖测试
This commit is contained in:
126
tests/agent/e2e-error.test.ts
Normal file
126
tests/agent/e2e-error.test.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from "bun:test";
|
||||
import { CommandLevelRunner } from "./tier1-command.ts";
|
||||
import { ScenarioRunner } from "./tier2-scenario.ts";
|
||||
import type { PlanOverride } from "./tier2-scenario.ts";
|
||||
import {
|
||||
setupTempDir,
|
||||
cleanupTempDir,
|
||||
getTempDir,
|
||||
createFreshProject,
|
||||
writeDoc,
|
||||
changeFileExists,
|
||||
} from "./fixtures.ts";
|
||||
import { assertNoFile } from "./validators.ts";
|
||||
import { scanChanges } from "../../src/core/scanner.ts";
|
||||
import { loadConfig } from "../../src/core/config.ts";
|
||||
import { mkdir, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { readFileSync } from "node:fs";
|
||||
|
||||
const brokenPlan: PlanOverride = async (_projectDir, changeName, docName, _cfg) => {
|
||||
const wrongDir = join(getTempDir(), "wrong-dir");
|
||||
await mkdir(wrongDir, { recursive: true });
|
||||
await writeFile(join(wrongDir, `${docName}.md`), "some content\n");
|
||||
|
||||
return {
|
||||
files: [],
|
||||
missed: [`${docName}.md`],
|
||||
};
|
||||
};
|
||||
|
||||
const emptyPlan: PlanOverride = async (_projectDir, _changeName, _docName, _cfg) => {
|
||||
return { files: [] };
|
||||
};
|
||||
|
||||
describe("e2e: 错误场景", () => {
|
||||
beforeEach(async () => {
|
||||
await setupTempDir();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await cleanupTempDir();
|
||||
});
|
||||
|
||||
it("agent 文件写错路径", async () => {
|
||||
const config = await createFreshProject();
|
||||
|
||||
const errorRunner = new ScenarioRunner(new CommandLevelRunner(), { plan: brokenPlan });
|
||||
const result = await errorRunner.runPlan(getTempDir(), "wrong-path", "design", config);
|
||||
|
||||
expect(result.files).toHaveLength(0);
|
||||
expect(result.missed).toEqual(["design.md"]);
|
||||
assertNoFile(getTempDir(), ".rune/changes/wrong-path/design.md");
|
||||
});
|
||||
|
||||
it("agent 跳过依赖文档", async () => {
|
||||
const config = await createFreshProject();
|
||||
|
||||
const skipDepsPlan: PlanOverride = async (_projectDir, changeName, docName, _cfg) => {
|
||||
const standardRunner = new CommandLevelRunner();
|
||||
|
||||
if (docName === "task") {
|
||||
return standardRunner.runPlan(getTempDir(), changeName, "task", config);
|
||||
}
|
||||
|
||||
if (docName === "design") {
|
||||
return standardRunner.runPlan(getTempDir(), changeName, "design", config);
|
||||
}
|
||||
|
||||
return { files: [] };
|
||||
};
|
||||
|
||||
const errorRunner = new ScenarioRunner(new CommandLevelRunner(), { plan: skipDepsPlan });
|
||||
|
||||
await errorRunner.runPlan(getTempDir(), "skip-deps", "task", config);
|
||||
|
||||
expect(changeFileExists("skip-deps", "task.md")).toBe(true);
|
||||
|
||||
let changes = await scanChanges(getTempDir(), config);
|
||||
expect(changes).toHaveLength(1);
|
||||
|
||||
const taskDoc = changes[0]!.documents.find((d) => d.name === "task");
|
||||
expect(taskDoc).toBeDefined();
|
||||
expect(taskDoc!.completed).toBe(true);
|
||||
expect(taskDoc!.dependMet).toBe(false);
|
||||
|
||||
const designDoc = changes[0]!.documents.find((d) => d.name === "design");
|
||||
expect(designDoc).toBeDefined();
|
||||
expect(designDoc!.completed).toBe(false);
|
||||
|
||||
await errorRunner.runPlan(getTempDir(), "skip-deps", "design", config);
|
||||
expect(changeFileExists("skip-deps", "design.md")).toBe(true);
|
||||
|
||||
changes = await scanChanges(getTempDir(), config);
|
||||
const taskDoc2 = changes[0]!.documents.find((d) => d.name === "task");
|
||||
expect(taskDoc2!.dependMet).toBe(true);
|
||||
});
|
||||
|
||||
it("agent 创建空文件", async () => {
|
||||
const config = await createFreshProject();
|
||||
|
||||
await writeDoc("empty-file", "design", "");
|
||||
|
||||
const errorRunner = new ScenarioRunner(new CommandLevelRunner(), { plan: emptyPlan });
|
||||
const result = await errorRunner.runPlan(getTempDir(), "empty-file", "design", config);
|
||||
|
||||
expect(changeFileExists("empty-file", "design.md")).toBe(true);
|
||||
|
||||
const filePath = join(getTempDir(), ".rune/changes/empty-file/design.md");
|
||||
const content = readFileSync(filePath, "utf-8");
|
||||
expect(content).toBe("");
|
||||
expect(result.files).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("config.yaml 语法错误", async () => {
|
||||
const runeDir = join(getTempDir(), ".rune");
|
||||
await mkdir(runeDir, { recursive: true });
|
||||
|
||||
const invalidYaml = "stages\n plan documents\n";
|
||||
await writeFile(join(runeDir, "config.yaml"), invalidYaml, "utf-8");
|
||||
|
||||
const loadedConfig = await loadConfig(getTempDir());
|
||||
expect(loadedConfig).toBeDefined();
|
||||
expect(loadedConfig.stages.plan).toBeDefined();
|
||||
expect(loadedConfig.stages.plan!.documents).toBeDefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user