revision-command.test.ts 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import { beforeEach, describe, expect, it, vi } from "vitest";
  2. const reviseDraftMock = vi.fn();
  3. const resyncChapterArtifactsMock = vi.fn();
  4. const buildPipelineConfigMock = vi.fn();
  5. const loadBookConfigMock = vi.fn();
  6. const logMock = vi.fn();
  7. const logErrorMock = vi.fn();
  8. vi.mock("@actalk/inkos-core", () => ({
  9. DEFAULT_REVISE_MODE: "spot-fix",
  10. PipelineRunner: class {
  11. reviseDraft = reviseDraftMock;
  12. resyncChapterArtifacts = resyncChapterArtifactsMock;
  13. },
  14. StateManager: class {
  15. async loadBookConfig() {
  16. return loadBookConfigMock();
  17. }
  18. },
  19. }));
  20. vi.mock("../utils.js", () => ({
  21. loadConfig: vi.fn(async () => ({ llm: {} })),
  22. buildPipelineConfig: buildPipelineConfigMock,
  23. findProjectRoot: vi.fn(() => "/project"),
  24. resolveBookId: vi.fn(async (bookId?: string) => bookId ?? "auto-book"),
  25. getLegacyMigrationHint: vi.fn(async () => undefined),
  26. resolveContext: vi.fn(),
  27. log: logMock,
  28. logError: logErrorMock,
  29. }));
  30. vi.mock("../localization.js", () => ({
  31. formatWriteNextResultLines: vi.fn(() => ["ok"]),
  32. resolveCliLanguage: vi.fn(() => "zh"),
  33. }));
  34. describe("revision-related CLI commands", () => {
  35. beforeEach(() => {
  36. vi.clearAllMocks();
  37. reviseDraftMock.mockResolvedValue({
  38. chapterNumber: 3,
  39. wordCount: 1200,
  40. fixedIssues: [],
  41. applied: true,
  42. status: "ready-for-review",
  43. });
  44. resyncChapterArtifactsMock.mockResolvedValue({
  45. chapterNumber: 3,
  46. title: "Synced Chapter",
  47. wordCount: 1200,
  48. revised: false,
  49. status: "ready-for-review",
  50. auditResult: { passed: true, issues: [], summary: "synced" },
  51. });
  52. buildPipelineConfigMock.mockReturnValue({});
  53. loadBookConfigMock.mockResolvedValue({ language: "zh" });
  54. });
  55. it("passes one-off brief into revise command pipeline config", async () => {
  56. const { reviseCommand } = await import("../commands/revise.js");
  57. await reviseCommand.parseAsync(["node", "revise", "demo-book", "3", "--mode", "rewrite", "--brief", "把注意力拉回师债主线。"], { from: "node" });
  58. expect(buildPipelineConfigMock).toHaveBeenCalledWith(expect.anything(), "/project", {
  59. externalContext: "把注意力拉回师债主线。",
  60. });
  61. expect(reviseDraftMock).toHaveBeenCalledWith("demo-book", 3, "rewrite");
  62. });
  63. it("exposes write sync and passes brief into pipeline config", async () => {
  64. const { writeCommand } = await import("../commands/write.js");
  65. await writeCommand.parseAsync(["node", "write", "sync", "demo-book", "3", "--brief", "以师债线为准同步状态。"], { from: "node" });
  66. expect(buildPipelineConfigMock).toHaveBeenCalledWith(expect.anything(), "/project", {
  67. externalContext: "以师债线为准同步状态。",
  68. });
  69. expect(resyncChapterArtifactsMock).toHaveBeenCalledWith("demo-book", 3);
  70. });
  71. });