Files
Rune-Spec/tests/cli/create.test.ts

109 lines
4.0 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 { existsSync } from "node:fs";
import { mkdir, rm } from "node:fs/promises";
import { join } from "node:path";
import { runInit } from "../../src/commands/init.ts";
import { loadConfig, getChangeDir } from "../../src/core/config.ts";
import { assemblePlanPrompt } from "../../src/core/assembler.ts";
import { CommandError } from "../../src/cli/errors.ts";
const TMP_DIR = join(import.meta.dir, "__tmp_create_test__");
beforeEach(async () => {
await mkdir(TMP_DIR, { recursive: true });
});
afterEach(async () => {
await rm(TMP_DIR, { recursive: true, force: true });
});
describe("create 命令(工具命令,非 SDD 阶段)", () => {
it("创建变更目录成功", async () => {
await runInit(TMP_DIR, ["opencode"]);
const changeDir = getChangeDir(TMP_DIR, "user-auth");
await mkdir(changeDir, { recursive: true });
expect(existsSync(changeDir)).toBe(true);
});
it("重复创建同名变更目录应报错", async () => {
await runInit(TMP_DIR, ["opencode"]);
const changeDir = getChangeDir(TMP_DIR, "duplicate-test");
await mkdir(changeDir, { recursive: true });
expect(existsSync(changeDir)).toBe(true);
// 再次创建同名目录不会报错mkdir recursive但 create 命令会检查
// 模拟 create 命令的检查逻辑
const prefix = "bunx @lanyuanxiaoyao/rune";
if (existsSync(changeDir)) {
// 应该抛出 CommandError
const err = new CommandError(`变更 "duplicate-test" 已存在`, {
hint: `请使用其他名称,或运行 ${prefix} status 查看现有变更`,
});
expect(err.message).toContain("duplicate-test");
expect(err.message).toContain("已存在");
}
});
it("create 后不再输出阶段提示词内容", async () => {
await runInit(TMP_DIR, ["opencode"]);
// 验证 create 不在 stages 配置中
const config = await loadConfig(TMP_DIR);
expect(config.stages.create).toBeUndefined();
});
it("create 不是 SDD 阶段常量之一", async () => {
const { STAGES } = await import("../../src/types.ts");
expect(STAGES).not.toContain("create");
expect(STAGES).toHaveLength(4);
});
});
describe("plan 命令前置检查", () => {
it("plan 在变更目录不存在时报错并提示 create", async () => {
await runInit(TMP_DIR, ["opencode"]);
const config = await loadConfig(TMP_DIR);
// 模拟 plan 命令检查:目录不存在
const changeDir = getChangeDir(TMP_DIR, "nonexistent-change");
expect(existsSync(changeDir)).toBe(false);
// 验证 plan 会报错
try {
await assemblePlanPrompt(config, TMP_DIR, "nonexistent-change", "design");
// assemblePlanPrompt 不检查目录存在,由 cli.ts 中的 plan 命令检查
// 这里只验证可以正常生成提示词(目录不存在不影响提示词生成)
} catch (e: any) {
// 如果抛错,应该不是由目录不存在引起的
expect(e.message).not.toContain("不存在");
}
});
it("plan 在变更目录存在时能正常生成提示词", async () => {
await runInit(TMP_DIR, ["opencode"]);
const config = await loadConfig(TMP_DIR);
const changeDir = getChangeDir(TMP_DIR, "existing-change");
await mkdir(changeDir, { recursive: true });
const prompt = await assemblePlanPrompt(config, TMP_DIR, "existing-change", "design");
expect(prompt).toBeTruthy();
expect(prompt).toContain("existing-change");
expect(prompt).toContain("design");
});
});
describe("变更名校验", () => {
it("合法变更名通过", () => {
const validRegex = /^[\u4e00-\u9fa5a-zA-Z-]+$/;
expect(validRegex.test("user-auth")).toBe(true);
expect(validRegex.test("用户登录")).toBe(true);
expect(validRegex.test("中文-english")).toBe(true);
});
it("非法变更名被拒绝", () => {
const validRegex = /^[\u4e00-\u9fa5a-zA-Z-]+$/;
expect(validRegex.test("my change")).toBe(false);
expect(validRegex.test("my_change")).toBe(false);
expect(validRegex.test("")).toBe(false);
});
});