Files
writer-work-flow/apps/web/lib/api/server.test.ts
Yaojia Wang c6651b74b9 fix(web): stale-closure + focus trap + 去边界强转 + a11y/性能打磨 + 类型化客户端
P1-6 useStyleLearn/useKimiOauth 修 stale-closure 依赖。
P1-7 CommandPalette/Drawer 加 focus trap(新 lib/a11y/focusTrap)。
P1-8 SSE 解析与 server.ts 去 as 强转改类型守卫/运行时校验。
P2 删冗余强转、开 noUncheckedIndexedAccess、Toast 清理+稳定 key、列表 key 稳定化、
  rel=noopener、useMemo 大文本、ConflictCard role=group、useInjection 加锁、
  client.test 真断言。
codegen 重生成 schema.d.ts + 消费 DimensionEntry/ReviewConflictView 强类型。
2026-06-21 19:32:49 +02:00

69 lines
1.8 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 { afterEach, describe, expect, it, vi } from "vitest";
import { fetchDraft, fetchOutline } from "./server";
// 纯加载/降级逻辑mock fetch无网络/DOM大纲解包/降级、草稿 404→null。
function mockFetch(status: number, body: unknown): void {
vi.stubGlobal(
"fetch",
vi.fn(async () =>
new Response(JSON.stringify(body), {
status,
headers: { "content-type": "application/json" },
}),
),
);
}
afterEach(() => {
vi.unstubAllGlobals();
});
describe("fetchOutline", () => {
it("returns the persisted chapters on 200", async () => {
mockFetch(200, { chapters: [{ no: 1, volume: 1, beats: ["开场"] }] });
const chapters = await fetchOutline("p1");
expect(chapters).toHaveLength(1);
expect(chapters[0]?.no).toBe(1);
});
it("returns empty array when the project has no outline", async () => {
mockFetch(200, { chapters: [] });
expect(await fetchOutline("p1")).toEqual([]);
});
it("falls back to empty array on any error (does not throw)", async () => {
mockFetch(404, { error: { code: "NOT_FOUND", message: "no project" } });
expect(await fetchOutline("missing")).toEqual([]);
});
});
describe("fetchDraft", () => {
it("returns the saved draft view on 200", async () => {
mockFetch(200, {
project_id: "p1",
chapter_no: 1,
volume: 1,
status: "draft",
version: 2,
content: "第一章正文",
length: 5,
});
const draft = await fetchDraft("p1", 1);
expect(draft?.content).toBe("第一章正文");
expect(draft?.version).toBe(2);
});
it("returns null when no draft exists (404 → empty editor)", async () => {
mockFetch(404, { error: { code: "NOT_FOUND", message: "no draft" } });
expect(await fetchDraft("p1", 9)).toBeNull();
});
});