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

157 lines
4.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 { describe, expect, it } from "vitest";
import {
PROCEED,
foldClarifications,
needsClarifyGate,
toVM,
type ClarifyAnswer,
} from "./clarify";
describe("foldClarifications", () => {
it("原意见在前,每条澄清另起一行并保序", () => {
const answers: ClarifyAnswer[] = [
{ question: "这段谁在说话?", answer: "主角内心独白" },
{ question: "结尾要留钩子吗?", answer: "留一个悬念" },
];
const result = foldClarifications("收紧节奏", answers);
expect(result).toBe(
"收紧节奏\n已澄清这段谁在说话 → 主角内心独白\n已澄清结尾要留钩子吗 → 留一个悬念",
);
});
it("无回答时原样返回去空白后的 instruction", () => {
expect(foldClarifications(" 收紧节奏 ", [])).toBe("收紧节奏");
});
it("instruction 为空时只输出澄清行", () => {
const answers: ClarifyAnswer[] = [
{ question: "谁在说话?", answer: "配角旁白" },
];
expect(foldClarifications(" ", answers)).toBe("已澄清:谁在说话? → 配角旁白");
});
it("跳过空/纯空白回答的条目", () => {
const answers: ClarifyAnswer[] = [
{ question: "Q1", answer: " " },
{ question: "Q2", answer: "有效回答" },
];
expect(foldClarifications("原意见", answers)).toBe(
"原意见\n已澄清Q2 → 有效回答",
);
});
it("问题为空(自由输入)时省略问题只留答案", () => {
const answers: ClarifyAnswer[] = [{ question: " ", answer: "就按我说的改" }];
expect(foldClarifications("原意见", answers)).toBe(
"原意见\n已澄清就按我说的改",
);
});
it("去除问题与答案两端空白", () => {
const answers: ClarifyAnswer[] = [
{ question: " 谁在说话? ", answer: " 主角 " },
];
expect(foldClarifications("x", answers)).toBe("x\n已澄清谁在说话 → 主角");
});
it("不可变:不修改入参数组", () => {
const answers: ClarifyAnswer[] = [{ question: "Q", answer: "A" }];
const snapshot = JSON.parse(JSON.stringify(answers));
foldClarifications("原意见", answers);
expect(answers).toEqual(snapshot);
});
it("全部为空回答且 instruction 为空时返回空串", () => {
expect(foldClarifications("", [{ question: "Q", answer: "" }])).toBe("");
});
});
describe("toVM", () => {
it("snake_case ClarifyDecision → camelCase VM逐字段映射", () => {
const vm = toVM({
need_clarification: true,
questions: [
{
question: "想更冷峻还是更抒情?",
options: [
{ label: "冷峻", value: "改得更冷峻克制" },
{ label: "抒情", value: "改得更抒情" },
],
allow_free_text: true,
},
],
verification: "我这样理解对吗",
});
expect(vm).toEqual({
needClarification: true,
questions: [
{
question: "想更冷峻还是更抒情?",
options: [
{ label: "冷峻", value: "改得更冷峻克制" },
{ label: "抒情", value: "改得更抒情" },
],
allowFreeText: true,
},
],
verification: "我这样理解对吗",
});
});
it("字段缺省时取安全默认(空/false/undefined不信任外部数据", () => {
const vm = toVM({});
expect(vm).toEqual({
needClarification: false,
questions: [],
verification: undefined,
});
});
it("questions/options 内字段缺省时逐项补默认", () => {
const vm = toVM({
need_clarification: true,
questions: [{ question: undefined, options: [{}], allow_free_text: undefined }],
verification: null,
});
expect(vm).toEqual({
needClarification: true,
questions: [
{ question: "", options: [{ label: "", value: "" }], allowFreeText: false },
],
verification: undefined,
});
});
});
describe("PROCEED", () => {
it("放行常量:不反问、无问题", () => {
expect(PROCEED).toEqual({ needClarification: false, questions: [] });
});
});
describe("needsClarifyGate", () => {
it("去空白后长度小于 minChars 时需要预检", () => {
expect(needsClarifyGate("改一下", 8)).toBe(true);
});
it("恰好等于 minChars 时不需预检(边界)", () => {
expect(needsClarifyGate("12345678", 8)).toBe(false);
});
it("超过 minChars 时不需预检", () => {
expect(needsClarifyGate("这是一段足够清晰具体的润色意见", 8)).toBe(false);
});
it("纯空白按空计(长度 0 < minChars需预检", () => {
expect(needsClarifyGate(" ", 8)).toBe(true);
});
it("先去两端空白再计长度", () => {
expect(needsClarifyGate(" 改 ", 2)).toBe(true);
});
});