接续 88dd570,保存 W20–W24 已实现的共享接口、业务入口、迁移、工作台、测试与文档。 W20/W22/W23 保持 in_progress,W21/W24 保持 verified;此提交不宣称方法或规则正式启用、多轮返修、真实角色评测完成。 W25 新增实验、标定、逐调用交付与角色执行及其迁移/测试/索引留在实施工作树,原有私人和旧实现保留项不纳入。 验证:离线 571、前端 33 通过;PG 469 项通过、2 项浏览器未启用,2 项误带入的 W25 用例已移出本提交;最终任务与交付边界 37 项通过。make 检查、最终类型、84 项资源及 diff 检查通过。未重跑浏览器或 Pi 宿主,不以合成调用认证外部模型效果。 独立整体审查四维通过;证据保存在 R2-20260909/提交W20-W24。
163 lines
8.0 KiB
TypeScript
163 lines
8.0 KiB
TypeScript
import { readFileSync, writeFileSync } from "node:fs";
|
||
import { expect, test } from "@playwright/test";
|
||
|
||
test.use({ trace: "off" });
|
||
test("NC-browser-author-review:规则诊断与声音确认使用真实后端", async ({
|
||
page,
|
||
}, info) => {
|
||
const pass = process.env.MUSE_AUTHOR_PASSWORD_FILE,
|
||
task = process.env.MUSE_REVIEW_TASK_ID;
|
||
if (!pass || !task) throw new Error("需要隔离服务、任务和作者口令位置");
|
||
const errors: string[] = [];
|
||
page.on("pageerror", (e) => errors.push(e.message));
|
||
await page.goto("/");
|
||
await page.getByLabel("访问口令").fill(readFileSync(pass, "utf8").trim());
|
||
await page.getByRole("button", { name: "进入工作台" }).click();
|
||
await page.getByRole("link", { name: /任务记录/ }).waitFor();
|
||
await page.goto("/review-rules");
|
||
await page.getByRole("button", { name: "导入内置候选规则" }).click();
|
||
await expect(
|
||
page.getByRole("heading", { name: "候选规则库 · 26 条" }),
|
||
).toBeVisible();
|
||
const r = page
|
||
.locator("section")
|
||
.filter({ has: page.getByRole("heading", { name: /空洞元话语/ }) });
|
||
await r.getByText("查看四类例证").click();
|
||
await expect(r.getByRole("heading", { name: "应保留" })).toBeVisible();
|
||
await page.goto(`/works/gen-work/review?chapter=ch-2&task=${task}`);
|
||
await expect(
|
||
page.getByRole("heading", { name: "完整文学报告" }),
|
||
).toBeVisible();
|
||
await page.getByLabel("预览候选规则(未标定)").check();
|
||
await page.getByRole("button", { name: "只读诊断机器味" }).click();
|
||
await expect(page.getByText(/候选规则预览 · 未标定/)).toBeVisible();
|
||
await page.screenshot({
|
||
path: `${info.outputDir}/文学与诊断.png`,
|
||
fullPage: true,
|
||
});
|
||
await page.getByRole("link", { name: "作品声音", exact: true }).click();
|
||
await page.getByLabel("声音样张").selectOption("ch-2");
|
||
await page
|
||
.getByLabel("句式画像", { exact: true })
|
||
.fill("短句推进,保留动作间停顿");
|
||
await page
|
||
.getByLabel("保护表达(每行一条,须出现在样张中)")
|
||
.fill("雨下了很久。");
|
||
await page.getByRole("button", { name: "保存声音候选" }).click();
|
||
await expect(page.getByText(/尚未确认声音/)).toBeVisible();
|
||
await page.getByRole("button", { name: "核对来源并打开审阅" }).click();
|
||
await page.getByRole("button", { name: "确认这版声音" }).click();
|
||
await expect(page.getByText("已确认版本 1")).toBeVisible();
|
||
await page.screenshot({
|
||
path: `${info.outputDir}/声音确认.png`,
|
||
fullPage: true,
|
||
});
|
||
await page.goto(`/works/gen-work/review?chapter=ch-2&task=${task}`);
|
||
await expect(page.getByText(/报告依据已变化/)).toBeVisible();
|
||
await page.getByLabel("审校配置").fill("review-config");
|
||
const response = page.waitForResponse(
|
||
(r) =>
|
||
r.url().endsWith("/literary-review-tasks") &&
|
||
r.request().method() === "POST",
|
||
);
|
||
await page.getByRole("button", { name: "发起完整文学审校" }).click();
|
||
const created = await response;
|
||
expect(created.status()).toBe(201);
|
||
const receipt = await created.json();
|
||
await expect(page.getByRole("heading", { name: "审校进度" })).toBeVisible();
|
||
writeFileSync(
|
||
`${info.outputDir}/审校回执.json`,
|
||
JSON.stringify({ created_task_id: receipt.task_id }),
|
||
);
|
||
await page.goto("/works/gen-work/review?chapter=ch-4");
|
||
await page.getByLabel("预览候选规则(未标定)").check();
|
||
await page.getByRole("button", { name: "只读诊断机器味" }).click();
|
||
await page.getByLabel(/批准修改这处发现/).check();
|
||
await page.getByLabel("本次修改目的").fill("删去作者认为没有功能的元话语");
|
||
await page.getByRole("button", { name: "生成修订候选" }).click();
|
||
await expect(page.getByText(/修订候选已保存,当前正文未变/)).toBeVisible();
|
||
await page.screenshot({
|
||
path: `${info.outputDir}/修订候选对照.png`,
|
||
fullPage: true,
|
||
});
|
||
await page.goto("/works/gen-work/review?chapter=ch-4");
|
||
await page.getByLabel("预览候选规则(未标定)").check();
|
||
await page.getByRole("button", { name: "只读诊断机器味" }).click();
|
||
await page.getByLabel("修订方式").selectOption("model");
|
||
await page.getByLabel(/批准修改这处发现/).check();
|
||
await page.getByLabel("本次修改目的").fill("让写手删除作者批准的元话语");
|
||
await page.getByLabel("修订配置").fill("gen-config");
|
||
await page.getByRole("button", { name: "发起一次模型修订" }).click();
|
||
await expect(
|
||
page.getByText("模型修订候选已保存,等待作者决定。"),
|
||
).toBeVisible({ timeout: 15000 });
|
||
await page.reload();
|
||
await expect(
|
||
page.getByText("模型修订候选已保存,等待作者决定。"),
|
||
).toBeVisible();
|
||
await expect(page.getByLabel(/批准修改这处发现/)).toBeChecked();
|
||
await expect(page.getByLabel("本次修改目的")).toHaveValue(
|
||
"让写手删除作者批准的元话语",
|
||
);
|
||
await page.screenshot({
|
||
path: `${info.outputDir}/模型修订回执.png`,
|
||
fullPage: true,
|
||
});
|
||
await page.goto("/works/gen-work/write/ch-4");
|
||
await page.getByRole("button", { name: "管理分支与合并" }).click();
|
||
await page.getByLabel("新分支名称").fill("雨后试写");
|
||
await page.getByRole("button", { name: "从当前保存版本创建分支" }).click();
|
||
await expect(page.getByText("分支已创建,原文仍保留。")).toBeVisible();
|
||
await page.getByRole("link", { name: "打开 雨后试写 · v1" }).click();
|
||
const editor = page.getByRole("textbox", { name: "章节正文" });
|
||
await expect(editor).toHaveText("值得注意的是,雨已经停了。");
|
||
await editor.click();
|
||
await page.keyboard.press("Meta+ArrowRight");
|
||
await page.keyboard.insertText("屋檐开始滴水。");
|
||
await expect(page.getByText("服务器已保存", { exact: true })).toBeVisible();
|
||
await page.getByRole("button", { name: "管理分支与合并" }).click();
|
||
await page.getByRole("button", { name: "与来源分支比较" }).click();
|
||
await page.getByLabel("合并修改 1", { exact: true }).check();
|
||
await page.getByRole("button", { name: "将所选修改生成合并候选" }).click();
|
||
await expect(page.getByText("合并候选已保存,目标正文未变。")).toBeVisible();
|
||
await page.screenshot({
|
||
path: `${info.outputDir}/分支合并对照.png`,
|
||
fullPage: true,
|
||
});
|
||
await page.getByRole("link", { name: "审阅合并候选" }).click();
|
||
await expect(
|
||
page.getByRole("heading", { name: "正文候选", exact: true }),
|
||
).toBeVisible();
|
||
await page.goto("/works/gen-work/write/ch-4");
|
||
await expect(page.getByRole("textbox", { name: "章节正文" })).toHaveText(
|
||
"值得注意的是,雨已经停了。",
|
||
);
|
||
const sourceEditor = page.getByRole("textbox", { name: "章节正文" });
|
||
await sourceEditor.click();
|
||
await page.keyboard.press("Meta+ArrowLeft");
|
||
for (let i = 0; i < 7; i++) await page.keyboard.press("ArrowRight");
|
||
for (let i = 0; i < 6; i++) await page.keyboard.press("Shift+ArrowRight");
|
||
await page.getByRole("button", { name: "使用当前圈选作为修改范围" }).click();
|
||
await page.getByLabel("选段目的").selectOption("polish");
|
||
await page.getByLabel("改写指示").fill("保留雨停这个事实,让表达更自然。");
|
||
await page.getByLabel("写手配置").fill("gen-config");
|
||
await page.getByRole("button", { name: "让写手按选段提出候选" }).click();
|
||
await expect(page.getByText("选段候选已保存,等待作者决定。")).toBeVisible({
|
||
timeout: 15000,
|
||
});
|
||
await page.reload();
|
||
await expect(page.getByText("选段候选已保存,等待作者决定。")).toBeVisible();
|
||
await expect(page.getByRole("textbox", { name: "章节正文" })).toHaveText(
|
||
"值得注意的是,雨已经停了。",
|
||
);
|
||
await page.screenshot({
|
||
path: `${info.outputDir}/通用选段回执.png`,
|
||
fullPage: true,
|
||
});
|
||
if (process.env.MUSE_BROWSER_INSPECT === "1")
|
||
await page.context().storageState({
|
||
path: `${process.env.MUSE_BROWSER_ARTIFACTS}/浏览器状态.json`,
|
||
});
|
||
expect(errors).toEqual([]);
|
||
});
|