muse-agent-example/web/tests/旅程/任务材料.spec.ts

104 lines
4.4 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 { readFileSync } from "node:fs";
import { expect, test } from "@playwright/test";
test.use({ trace: "off" });
test("NC-browser-context-workbench:任务材料清单、来源证据与失效说明", async ({
page,
}, info) => {
if (!process.env.MUSE_WORKBENCH_URL || !process.env.MUSE_AUTHOR_PASSWORD_FILE)
throw new Error("需要明确的隔离后端和作者口令文件。");
const taskId = process.env.MUSE_CONTEXT_TASK_ID!;
const chapterId = process.env.MUSE_CONTEXT_CHAPTER_ID ?? "ch-1";
if (!process.env.MUSE_CONTEXT_TASK_ID)
throw new Error("需要带冻结快照的任务编号(MUSE_CONTEXT_TASK_ID)。");
const consoleErrors: string[] = [];
page.on("pageerror", (error) => consoleErrors.push(String(error)));
await page.goto("/");
await page
.getByLabel("访问口令")
.fill(readFileSync(process.env.MUSE_AUTHOR_PASSWORD_FILE, "utf8").trim());
await page.getByRole("button", { name: "进入工作台" }).click();
await page.getByRole("link", { name: /任务记录/ }).waitFor();
// 连接前探测会话的 401 与 favicon 404 属正常噪声;只记录进入工作台后的真实错误。
page.on("console", (message) => {
if (message.type() === "error" && !/favicon/.test(message.text()))
consoleErrors.push(message.text());
});
async function 打开任务() {
await page.goto("/tasks");
await page.getByLabel("任务编号").fill(taskId);
await page.getByRole("button", { name: "查看任务" }).click();
await expect(
page.locator('section[aria-label="任务材料"]'),
).toBeVisible();
}
await 打开任务();
const 材料 = page.locator('section[aria-label="任务材料"]');
await expect(材料.getByText("材料快照 01")).toBeVisible();
await expect(材料.getByText("仍可用于回读")).toBeVisible();
await expect(材料.getByText("历史:ch-1")).toBeVisible();
await expect(材料.getByText("已按冻结版本装配")).toBeVisible();
await expect(材料.getByText("参考:超长素材")).toBeVisible();
await expect(
材料.getByText("省略原因:超出材料预算,整项省略"),
).toBeVisible();
await expect(材料.getByText(/材料 \d+ 字节/)).toBeVisible();
await expect(材料.getByText(/文本哈希 [0-9a-f]{64}/)).toBeVisible();
await expect(材料.getByText("来源证据")).toBeVisible();
await expect(材料.getByText("1 处来源")).toBeVisible();
await expect(材料.getByText("版本 1", { exact: true })).toBeVisible();
await expect(
材料.getByText(/visible-text-codepoints\/v1:production:generation/),
).toBeVisible();
await expect(材料.getByText("仍有效")).toBeVisible();
// 造一处真实漂移:以当前正文版本为基线保存新版本,冻结快照的来源随即失效。
const 当前 = await (
await page.request.get(`/api/v1/chapters/${chapterId}/documents`)
).json();
const save = await page.request.post(`/api/v1/chapters/${chapterId}/documents`, {
headers: { Origin: process.env.MUSE_WORKBENCH_URL },
data: {
command_id: `browser-drift-revision-${当前.revision}`,
chapter_id: chapterId,
expected_revision: 当前.revision,
document: {
format_version: 1,
paragraphs: [
{
paragraph_id: "p-2",
content: [{ type: "text", text: "第二天清晨,雨停了。", marks: [] }],
},
],
},
},
});
expect(save.ok()).toBeTruthy();
await 打开任务();
await expect(材料.getByText("来源已漂移,需重新授权")).toBeVisible();
await expect(材料.getByText(/文稿 ch-1 已漂移/)).toBeVisible();
await expect(
材料.getByText(/文稿 ch-1 已从版本 \d+ 前进到 \d+/),
).toBeVisible();
await expect(材料.getByText("已漂移", { exact: true })).toBeVisible();
// 失效不改写历史装配:清单与省略原因仍按冻结时原样显示。
await expect(材料.getByText("历史:ch-1")).toBeVisible();
await expect(
材料.getByText("省略原因:超出材料预算,整项省略"),
).toBeVisible();
await expect(材料.getByText("版本 1", { exact: true })).toBeVisible();
await page.screenshot({
path: info.outputPath("任务材料与失效说明.png"),
fullPage: true,
});
expect(consoleErrors, `浏览器控制台错误:${consoleErrors.join(" | ")}`).toEqual(
[],
);
});