- 上下文清单、任务列表与详情、恢复控制、运行观察、创作对话与消息流、正式变更决策面板、正文写作与候选审阅、资料研究等页面同步本轮后端能力。 - 事件标签表补齐后端事件类型;查询键与生成客户端随 HTTP 契约重新生成。 - 依赖调整后 lockfile 同步;交互用例与浏览器旅程 spec 一并更新。 - 证据:make 前端检查(lint + typecheck + Pi 工具桥 tsc)exit 0;make 前端测试 37 文件 / 120 用例通过。
149 lines
5.7 KiB
TypeScript
149 lines
5.7 KiB
TypeScript
import { execFileSync } from "node:child_process";
|
||
import { readFileSync, writeFileSync } from "node:fs";
|
||
import { expect, test } from "@playwright/test";
|
||
|
||
// @muse-case {"case_id":"NC-browser-rule-improvement","environment":"隔离PG/合成HTTP及浏览器","given":"固定请求、来源与作者;按用例环境准备独立测试输入","when":"通过实际公开入口执行并核对拒绝、状态及持久结果","then":["NC-browser-rule-improvement:反馈提案经实际验证后明确启停并读回诊断"],"contract":"docs/系统架构/新版设计/模块设计/B07-作者经验.md#有来源的运行观察"}
|
||
test("NC-browser-rule-improvement:反馈提案经实际验证后明确启停并读回诊断", async ({
|
||
page,
|
||
}, info) => {
|
||
const env = process.env;
|
||
const password = env.MUSE_AUTHOR_PASSWORD_FILE;
|
||
const feedback = env.MUSE_FEEDBACK_ID;
|
||
const python = env.MUSE_TEST_PYTHON;
|
||
const production = env.MUSE_PRODUCTION_CONFIG;
|
||
const evaluation = env.MUSE_EVALUATION_CONFIG;
|
||
const maintenance = env.MUSE_MAINTENANCE_CONFIG;
|
||
const dataset = env.MUSE_RULE_DATASET_ID;
|
||
const target = env.MUSE_RULE_BODY_TARGET;
|
||
if (
|
||
!password ||
|
||
!feedback ||
|
||
!python ||
|
||
!production ||
|
||
!evaluation ||
|
||
!maintenance ||
|
||
!dataset ||
|
||
!target
|
||
)
|
||
throw new Error("需要独立测试配置、反馈、确切规则样本及正文");
|
||
const errors: string[] = [];
|
||
page.on("pageerror", (error) => errors.push(error.message));
|
||
await page.goto("/");
|
||
await page.getByLabel("访问口令").fill(readFileSync(password, "utf8").trim());
|
||
await page.getByRole("button", { name: "进入工作台" }).click();
|
||
await page.goto(`/improvements/new?feedback=${feedback}`);
|
||
await page.getByRole("combobox", { name: "改进目标", exact: true }).selectOption("rule");
|
||
await page.getByLabel("改进标题").fill("提示语规则的反馈验证");
|
||
await page
|
||
.getByLabel("需要验证的改变")
|
||
.fill("识别提示语,同时保留人物有意的口头禅。");
|
||
await page.getByLabel("具体规则版本").selectOption("l002");
|
||
const created = page.waitForResponse(
|
||
(response) =>
|
||
response.url().endsWith("/api/v1/rule-improvements") &&
|
||
response.request().method() === "POST",
|
||
);
|
||
await page.getByRole("button", { name: "保存规则改进提案" }).click();
|
||
const response = await created;
|
||
expect(response.status()).toBe(201);
|
||
const row = await response.json();
|
||
await expect(
|
||
page.getByRole("heading", { name: "提示语规则的反馈验证", exact: true }),
|
||
).toBeVisible();
|
||
await expect(page.getByText("本提案规则尚未启用。")).toBeVisible();
|
||
await expect(
|
||
page.getByRole("button", { name: "核对凭据并打开启用审阅" }),
|
||
).toBeDisabled();
|
||
|
||
// 评测用途由测试驱动显式调用真实CLI,作者服务不持有或推导评测凭据。
|
||
const validationFile = info.outputPath("验证请求.json");
|
||
writeFileSync(
|
||
validationFile,
|
||
JSON.stringify({
|
||
command_id: "browser-rule-improvement-validate",
|
||
selection: {
|
||
improvement_id: row.improvement_id,
|
||
revision: row.revision,
|
||
content_hash: row.content_hash,
|
||
},
|
||
request: {
|
||
dataset_version_id: dataset,
|
||
rule_id: row.payload.rule_id,
|
||
rule_version: row.payload.rule_version,
|
||
rule_hash: row.payload.rule_hash,
|
||
},
|
||
}),
|
||
);
|
||
const result = JSON.parse(
|
||
execFileSync(
|
||
python,
|
||
[
|
||
"-I",
|
||
"-m",
|
||
"muse",
|
||
"经验",
|
||
production,
|
||
"申请规则验证",
|
||
validationFile,
|
||
"--评测配置",
|
||
evaluation,
|
||
],
|
||
{ encoding: "utf8", timeout: 30000 },
|
||
),
|
||
);
|
||
const exportFile = info.outputPath("导出请求.json");
|
||
writeFileSync(
|
||
exportFile,
|
||
JSON.stringify({
|
||
run_id: result.receipt.run_id,
|
||
approval_ref: "fixture-rule-improvement-browser",
|
||
valid_until: new Date(Date.now() + 3600000).toISOString(),
|
||
}),
|
||
);
|
||
const proof = JSON.parse(
|
||
execFileSync(
|
||
python,
|
||
["-I", "-m", "muse", "评测", maintenance, "导出规则凭据", exportFile],
|
||
{ encoding: "utf8", timeout: 30000 },
|
||
),
|
||
);
|
||
await page.reload();
|
||
await expect(
|
||
page.getByText("实际验证结果已关联", { exact: true }),
|
||
).toBeVisible();
|
||
await page.getByLabel("规则验证凭据编号").fill(proof.receipt_id);
|
||
await page.getByRole("button", { name: "核对凭据并打开启用审阅" }).click();
|
||
await expect(page.getByText("本提案规则尚未启用。")).toBeVisible();
|
||
await page.getByRole("button", { name: "确认启用此规则版本" }).click();
|
||
await expect(
|
||
page.getByText("本提案第1版已启用,可用于只读诊断。"),
|
||
).toBeVisible();
|
||
const diagnosis = await page.evaluate(async (body) => {
|
||
const response = await fetch("/api/v1/diagnoses", {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({ target: JSON.parse(body) }),
|
||
});
|
||
if (response.status !== 201) throw new Error(await response.text());
|
||
return response.json();
|
||
}, target);
|
||
await page.reload();
|
||
await expect(
|
||
page.getByRole("link", { name: `查看诊断 ${diagnosis.diagnosis_id}` }),
|
||
).toBeVisible();
|
||
await page.screenshot({
|
||
path: info.outputPath("规则改进与实际诊断.png"),
|
||
fullPage: true,
|
||
});
|
||
await page.getByRole("button", { name: "核对停用依据" }).click();
|
||
await page.getByRole("button", { name: "确认停用此规则版本" }).click();
|
||
await expect(
|
||
page.getByText("本提案规则已停用。", { exact: true }),
|
||
).toBeVisible();
|
||
await page.reload();
|
||
await expect(
|
||
page.getByText("本提案规则已停用。", { exact: true }),
|
||
).toBeVisible();
|
||
expect(errors).toEqual([]);
|
||
});
|