Files
story/scripts/visual-ops-config-ui.cjs

61 lines
4.3 KiB
JavaScript
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.
const path = require("path");
const fs = require("fs");
const root = process.env.PLAYWRIGHT_REQUIRE_FROM;
if (!root) throw new Error("PLAYWRIGHT_REQUIRE_FROM is required");
const { chromium } = require(path.join(root, "playwright"));
const chromePath = process.env.CHROME_PATH || "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe";
const outputDir = path.resolve(process.env.UI_SCREENSHOT_DIR || "test/e2e/screenshots/operations");
fs.mkdirSync(outputDir, { recursive: true });
(async () => {
const browser = await chromium.launch({ executablePath: chromePath, headless: true });
const page = await browser.newPage({ viewport: { width: 1440, height: 1100 } });
const failures = [];
page.on("pageerror", (error) => failures.push(`pageerror: ${error.message}`));
page.on("console", (message) => { if (message.type() === "error") failures.push(`console: ${message.text()}`); });
page.on("response", (response) => { if (response.status() >= 400) failures.push(`http ${response.status()}: ${response.url()}`); });
await page.goto("http://localhost:3100", { waitUntil: "networkidle" });
const login = page.getByRole("button", { name: "登录研发环境" });
if (await login.isVisible()) {
await login.click();
await page.locator("#username").fill("owner");
await page.locator("#password").fill("LocalOnly123!");
await page.locator("#kc-login").click();
}
await page.waitForURL("http://localhost:3100/**", { timeout: 15000 });
await page.getByRole("button", { name: /^运行配置/ }).click();
await page.getByRole("heading", { name: "配置发布与版本控制" }).waitFor({ state: "visible", timeout: 10000 });
await page.getByLabel("配置类型").selectOption("AGENT_BUNDLE");
await page.locator(".ops-bundle-composer").waitFor({ state: "visible" });
const componentLabels = ["人设版本", "音色版本", "模型版本", "路由版本"];
for (const label of componentLabels) {
const selector = page.getByLabel(label);
if (await selector.count() !== 1) failures.push(`missing Agent bundle selector: ${label}`);
if (process.env.EXPECT_AGENT_BUNDLE_COMPONENTS === "1") {
const optionCount = await selector.locator("option").count();
if (optionCount < 2) failures.push(`Agent bundle selector has no published component: ${label}`);
if (await selector.inputValue() === "") failures.push(`Agent bundle selector was not automatically selected: ${label}`);
}
}
if (await page.getByLabel("配置正文(JSON)").count()) failures.push("Agent bundle still exposes raw JSON editor");
if (!await page.getByText("组合不直接保存密钥引用").isVisible()) failures.push("Agent bundle credential ownership note is missing");
if (!await page.getByText("配置投放控制", { exact: true }).isVisible()) failures.push("rollout control ledger is missing");
if (process.env.EXPECT_ROLLOUT_CONTROLS === "1" && await page.getByRole("button", { name: /^(暂停|恢复)$/ }).count() < 1) {
failures.push("active or paused rollout has no control action");
}
if (process.env.EXERCISE_ROLLOUT_CONTROLS === "1") {
const pauseButton = page.getByRole("button", { name: "暂停", exact: true }).first();
await Promise.all([page.waitForEvent("dialog").then((dialog) => dialog.accept("浏览器纵向冒烟暂停")), pauseButton.click()]);
await page.getByText("配置投放已暂停,后续新建通话不再命中该范围。").waitFor({ state: "visible", timeout: 10000 });
const resumeButton = page.getByRole("button", { name: "恢复", exact: true }).first();
await Promise.all([page.waitForEvent("dialog").then((dialog) => dialog.accept("浏览器纵向冒烟恢复")), resumeButton.click()]);
await page.getByText("配置投放已恢复,后续新建通话可再次命中该范围。").waitFor({ state: "visible", timeout: 10000 });
}
const overflow = await page.evaluate(() => document.documentElement.scrollWidth > document.documentElement.clientWidth + 1);
if (overflow) failures.push("operations workspace has horizontal overflow");
await page.screenshot({ path: path.join(outputDir, "ops-config-workspace.png"), fullPage: true });
await browser.close();
if (failures.length) throw new Error(failures.join("\n"));
process.stdout.write(`Operations config UI browser smoke passed. Screenshot: ${outputDir}\n`);
})().catch((error) => { process.stderr.write(`${error.stack || error}\n`); process.exitCode = 1; });