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

127 lines
4.2 KiB
TypeScript

import { describe, it, expect, beforeEach, afterEach } from "bun:test";
import { CommandLevelRunner } from "./agent-mock.ts";
import { ScenarioRunner } from "./agent-scenario.ts";
import type { PlanOverride } from "./agent-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();
});
});