Files
mnote/wolai-frontend/src/app/api/documents/route-adapters.test.ts
T
lix-2026 d148e1ccc2 feat: 收口本地文件夹入口并推进 page aggregate rust-first
- 为 Rust Web 主入口补齐本地文件夹/云空间切换、最近目录与路径回填体验\n- 对齐 local markdown media 与 inline marks 的 Rust shell / TipTap converter 语义\n- 让 documents/page 优先消费 Rust page aggregate snapshot,并保留 TS fallback\n- 补强 tree live、local markdown 与主入口 smoke,并同步设计稿状态
2026-05-09 19:05:06 +08:00

222 lines
7.4 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from "vitest";
vi.mock("@/lib/convex/enabled", () => ({
isConvexEnabled: vi.fn(() => true),
}));
vi.mock("@/lib/auth/authContext", () => ({
HttpError: class HttpError extends Error {
status: number;
constructor(status: number, message: string) {
super(message);
this.status = status;
}
},
requireAuthContext: vi.fn(async () => ({
userId: "user_1",
})),
}));
vi.mock("@/lib/api-utils", () => ({
apiErrorResponse: vi.fn((message: string, status = 500, details?: unknown) => ({
message,
status,
details,
})),
}));
vi.mock("@/lib/documents/page-command-adapter", () => ({
executeDocumentCreateChildBridgeCommand: vi.fn(async () => new Response(JSON.stringify({ ok: true }))),
executeDocumentTemplateBridgeCommand: vi.fn(async () => new Response(JSON.stringify({ ok: true }))),
executeDocumentEmptyTrashBridgeCommand: vi.fn(async () => new Response(JSON.stringify({ ok: true }))),
}));
vi.mock("@/lib/documents/page-write-command-adapter", () => ({
executePageWriteBridgeCommand: vi.fn(async () => ({
requestId: "req_1",
traceId: "trace_1",
commandId: "cmd_1",
commandName: "page.command",
revision: 1,
conflictDetectionKey: "doc_1:1",
})),
}));
vi.mock("@/lib/documents/page-aggregate-loader", () => ({
loadPageAggregate: vi.fn(async () => ({
page: {
identity: { documentId: "doc_1", workspaceId: "ws_1" },
head: {
title: "页面标题",
updatedAt: null,
permissions: {
readOnly: false,
disableDownload: false,
disableCopy: false,
},
},
layout: { pageOptions: { wideLayout: false } },
body: { content: null, revision: 0, conflictDetectionKey: "doc_1:0" },
tree: { pageSubtree: null },
stats: null,
},
bridge: {
requestId: "req_1",
traceId: "trace_1",
queryName: "documents.page.get",
},
})),
}));
import { POST as postCreateChild } from "@/app/api/documents/create-child/route";
import { POST as postTemplate } from "@/app/api/documents/template/route";
import { POST as postEmptyTrash } from "@/app/api/documents/empty-trash/route";
import { POST as postTitle } from "@/app/api/documents/title/route";
import { POST as postOptions } from "@/app/api/documents/options/route";
import { POST as postSave } from "@/app/api/documents/save/route";
import { GET as getPage } from "@/app/api/documents/page/route";
import {
executeDocumentCreateChildBridgeCommand,
executeDocumentTemplateBridgeCommand,
executeDocumentEmptyTrashBridgeCommand,
} from "@/lib/documents/page-command-adapter";
import { executePageWriteBridgeCommand } from "@/lib/documents/page-write-command-adapter";
import { loadPageAggregate } from "@/lib/documents/page-aggregate-loader";
afterEach(() => {
vi.restoreAllMocks();
vi.clearAllMocks();
});
describe("documents route adapters", () => {
it("title route 在树重命名兼容请求下委托 tree commands 主路径", async () => {
const fetchMock = vi.spyOn(globalThis, "fetch").mockResolvedValue(
new Response(
JSON.stringify({
requestId: "req_tree_rename_1",
traceId: "trace_tree_rename_1",
result: {
action: "rename",
workspaceId: "ws_1",
documentId: "doc_1",
title: "新标题",
updatedAt: "2026-04-23T00:00:00Z",
},
}),
{ status: 200, headers: { "content-type": "application/json" } },
),
);
const response = await postTitle(new Request("http://localhost/api/documents/title", {
method: "POST",
headers: {
"authorization": "Bearer test-token",
"content-type": "application/json",
"cookie": "convex-auth=test-cookie",
},
body: JSON.stringify({ documentId: "doc_1", workspaceId: "ws_1", title: "新标题" }),
}));
const payload = await response.json() as {
ok: boolean;
meta: { commandName: string };
};
expect(fetchMock).toHaveBeenCalledWith(
"http://localhost/api/tree/commands",
expect.objectContaining({
method: "POST",
headers: expect.any(Headers),
body: JSON.stringify({
action: "rename",
documentId: "doc_1",
workspaceId: "ws_1",
title: "新标题",
}),
}),
);
const renameCall = fetchMock.mock.calls.find(([, init]) => {
if (!init || typeof init.body !== "string") {
return false;
}
return init.body.includes('"action":"rename"');
});
const forwardedHeaders = renameCall?.[1]?.headers as Headers;
expect(forwardedHeaders.get("authorization")).toBe("Bearer test-token");
expect(forwardedHeaders.get("cookie")).toBe("convex-auth=test-cookie");
expect(payload.ok).toBe(true);
expect(payload.meta.commandName).toBe("tree.node.rename");
});
it("creates child route delegates to unified adapter", async () => {
await postCreateChild(new Request("http://localhost/api/documents/create-child", {
method: "POST",
body: JSON.stringify({ parentId: null }),
}));
expect(executeDocumentCreateChildBridgeCommand).toHaveBeenCalled();
});
it("template route delegates to unified adapter", async () => {
await postTemplate(new Request("http://localhost/api/documents/template", {
method: "POST",
body: JSON.stringify({ documentId: "doc_1", isTemplate: true }),
}));
expect(executeDocumentTemplateBridgeCommand).toHaveBeenCalled();
});
it("empty trash route delegates to unified adapter", async () => {
await postEmptyTrash(new Request("http://localhost/api/documents/empty-trash", {
method: "POST",
body: JSON.stringify({ workspaceId: "ws_1" }),
}));
expect(executeDocumentEmptyTrashBridgeCommand).toHaveBeenCalled();
});
it("page route delegates to unified aggregate loader", async () => {
const response = await getPage(
new Request("http://localhost/api/documents/page?documentId=doc_1&workspaceId=ws_1"),
);
const payload = await response.json() as {
page: { identity: { documentId: string } };
meta: { queryName: string };
};
expect(loadPageAggregate).toHaveBeenCalled();
expect(response.status).toBe(200);
expect(payload.page.identity.documentId).toBe("doc_1");
expect(payload.meta.queryName).toBe("documents.page.get");
});
it("title route 在 page head 请求下仍委托 unified page write adapter", async () => {
await postTitle(new Request("http://localhost/api/documents/title", {
method: "POST",
body: JSON.stringify({
documentId: "doc_1",
workspaceId: "ws_1",
title: "新标题",
commandName: "page.head.updateTitle",
}),
}));
expect(executePageWriteBridgeCommand).toHaveBeenCalled();
});
it("options route delegates to unified page write adapter", async () => {
await postOptions(new Request("http://localhost/api/documents/options", {
method: "POST",
body: JSON.stringify({ documentId: "doc_1", workspaceId: "ws_1", options: { wideLayout: true } }),
}));
expect(executePageWriteBridgeCommand).toHaveBeenCalled();
});
it("save route delegates to unified page write adapter", async () => {
await postSave(new Request("http://localhost/api/documents/save", {
method: "POST",
body: JSON.stringify({ documentId: "doc_1", workspaceId: "ws_1", content: [] }),
}));
expect(executePageWriteBridgeCommand).toHaveBeenCalled();
});
});