feat: complete tree shell cutover and regression coverage

This commit is contained in:
lix-2026
2026-04-18 09:38:16 +08:00
parent d3876e56eb
commit 111a87d4fd
53 changed files with 5440 additions and 516 deletions
@@ -0,0 +1,54 @@
import { afterEach, describe, expect, it, vi } from "vitest";
import {
copyTreeCommand,
createDocumentCommand,
deleteDocumentCommand,
embedDocumentCommand,
moveDocumentCommand,
purgeDocumentCommand,
renameDocumentCommand,
restoreDocumentCommand,
} from "@/lib/documents/tree-command-client";
describe("tree-command-client", () => {
afterEach(() => {
vi.restoreAllMocks();
});
it("通过统一 client 发送 tree/document command 并返回结果", async () => {
const fetchMock = vi.spyOn(globalThis, "fetch").mockResolvedValue({
ok: true,
json: async () => ({ ok: true, success: true, items: [] }),
} as Response);
await createDocumentCommand(null);
await renameDocumentCommand({ documentId: "doc_1", title: "新标题" });
await moveDocumentCommand({ documentId: "doc_1", parentId: null, position: 0 });
await deleteDocumentCommand({ documentId: "doc_1" });
await restoreDocumentCommand({ documentId: "doc_1" });
await purgeDocumentCommand({ documentId: "doc_1" });
await embedDocumentCommand({ sourceId: "doc_1", targetId: "doc_2" });
await copyTreeCommand({ targetParentId: null, items: [{ documentId: "doc_1", recursive: true }] });
expect(fetchMock).toHaveBeenCalledTimes(8);
expect(fetchMock.mock.calls.map((call) => String(call[0]))).toEqual([
"/api/documents/create",
"/api/documents/title",
"/api/documents/move",
"/api/documents/delete",
"/api/documents/restore",
"/api/documents/purge",
"/api/documents/embed",
"/api/documents/copy-tree",
]);
});
it("在后端返回错误时抛出统一异常", async () => {
vi.spyOn(globalThis, "fetch").mockResolvedValue({
ok: false,
json: async () => ({ error: "删除失败" }),
} as Response);
await expect(deleteDocumentCommand({ documentId: "doc_1" })).rejects.toThrow("删除失败");
});
});
@@ -11,6 +11,41 @@ type DocumentCommandErrorPayload = {
error?: string;
};
export const TREE_COMMAND_PROTOCOL = {
create: {
preferredCommandName: "tree.node.create",
compatCommandName: "documents.create",
},
rename: {
preferredCommandName: "tree.node.rename",
compatCommandName: "documents.title.update",
},
move: {
preferredCommandName: "tree.subtree.move",
compatCommandName: "documents.move",
},
archive: {
preferredCommandName: "tree.node.archive",
compatCommandName: "documents.delete",
},
restore: {
preferredCommandName: "tree.node.restore",
compatCommandName: "documents.restore",
},
purge: {
preferredCommandName: "tree.node.purge",
compatCommandName: "documents.purge",
},
embed: {
preferredCommandName: "tree.node.embed",
compatCommandName: "documents.embed",
},
copy: {
preferredCommandName: "tree.subtree.copy",
compatCommandName: "documents.copy_tree",
},
} as const;
export type DocumentCreateCommandResult = {
id: string;
title?: string | null;