Files
writer-work-flow/apps/web/lib/workbench/useRewriteClarify.test.ts

116 lines
4.2 KiB
TypeScript
Raw Permalink 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.

// @vitest-environment jsdom
import { act, renderHook } from "@testing-library/react";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { useRewriteClarify } from "./useRewriteClarify";
import type { ClarifyDecisionVM } from "./clarify";
const post = vi.fn();
vi.mock("@/lib/api/client", () => ({
api: { POST: (...a: unknown[]) => post(...a) },
}));
const CLARIFY_PATH = "/projects/{project_id}/chapters/{chapter_no}/rewrite/clarify";
describe("useRewriteClarify", () => {
beforeEach(() => post.mockReset());
afterEach(() => vi.clearAllMocks());
it("初始 idle、无决策", () => {
const { result } = renderHook(() => useRewriteClarify());
expect(result.current.status).toBe("idle");
expect(result.current.decision).toBeNull();
});
it("need_clarification=truePOST rewrite/clarify 带 feedback+prior_draft映射 VMstatus=asking", async () => {
post.mockResolvedValue({
data: {
need_clarification: true,
questions: [
{
question: "高潮想更爽还是更虐?",
options: [
{ label: "更爽", value: "把高潮写得更爽快" },
{ label: "更虐", value: "把高潮写得更虐" },
],
allow_free_text: true,
},
],
verification: null,
},
error: null,
});
const { result } = renderHook(() => useRewriteClarify());
let vm: ClarifyDecisionVM | undefined;
await act(async () => {
vm = await result.current.check("p1", 3, "改改", "整章草稿正文");
});
expect(post).toHaveBeenCalledWith(CLARIFY_PATH, {
params: { path: { project_id: "p1", chapter_no: 3 } },
body: { feedback: "改改", prior_draft: "整章草稿正文" },
});
expect(vm).toEqual({
needClarification: true,
questions: [
{
question: "高潮想更爽还是更虐?",
options: [
{ label: "更爽", value: "把高潮写得更爽快" },
{ label: "更虐", value: "把高潮写得更虐" },
],
allowFreeText: true,
},
],
verification: undefined,
});
expect(result.current.status).toBe("asking");
expect(result.current.decision?.needClarification).toBe(true);
});
it("need_clarification=falsestatus=proceeddecision 清空", async () => {
post.mockResolvedValue({
data: { need_clarification: false, questions: [], verification: "我按你说的拉满高潮" },
error: null,
});
const { result } = renderHook(() => useRewriteClarify());
let vm: ClarifyDecisionVM | undefined;
await act(async () => {
vm = await result.current.check("p1", 1, "把第 3 段的高潮再拉满,删掉闪回", "草稿");
});
expect(vm?.needClarification).toBe(false);
expect(result.current.status).toBe("proceed");
expect(result.current.decision).toBeNull();
});
it("后端 error视为放行proceedneedClarification=false不阻塞重写", async () => {
post.mockResolvedValue({ data: null, error: { detail: "boom" } });
const { result } = renderHook(() => useRewriteClarify());
let vm: ClarifyDecisionVM | undefined;
await act(async () => {
vm = await result.current.check("p1", 1, "改", "草稿");
});
expect(vm?.needClarification).toBe(false);
expect(result.current.status).toBe("proceed");
});
// 注hook 的 try/catch 对「fetch 抛异常」的放行分支与上面「后端 error 信封」放行分支同构、
// 行为一致(均 status=proceed、needClarification=false、返回 PROCEED此处不单测 throw 路径,
// 因 mock 抛错 + React act 冲刷会触发 vitest 未处理错误误报(与被测逻辑无关,同 M1 useClarify.test.ts
it("reset 清回 idle", async () => {
post.mockResolvedValue({
data: { need_clarification: true, questions: [{ question: "q", options: [], allow_free_text: true }] },
error: null,
});
const { result } = renderHook(() => useRewriteClarify());
await act(async () => {
await result.current.check("p1", 1, "改", "草稿");
});
act(() => result.current.reset());
expect(result.current.status).toBe("idle");
expect(result.current.decision).toBeNull();
});
});