Agent task: 开发: Phase A+E+F — CSS 全量改造 (mnote-web)
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
"use strict";
|
||||
|
||||
const { chromium } = require("playwright");
|
||||
const { BASE_URL, UI_TIMEOUT_MS, assert, ensureAuthenticated } = require("./tree-shell-smoke-helpers");
|
||||
|
||||
const MNOTE_WEB_ENABLE_DEBUG_SHELL_ROUTES = process.env.MNOTE_WEB_ENABLE_DEBUG_SHELL_ROUTES || "0";
|
||||
|
||||
if (MNOTE_WEB_ENABLE_DEBUG_SHELL_ROUTES !== "1") {
|
||||
console.log("[task500] 跳过: MNOTE_WEB_ENABLE_DEBUG_SHELL_ROUTES 未设为 1 (当前值: '%s')", MNOTE_WEB_ENABLE_DEBUG_SHELL_ROUTES);
|
||||
console.log("[task500] 设置 MNOTE_WEB_ENABLE_DEBUG_SHELL_ROUTES=1 并重启 mnote-web 后再运行此 smoke。");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const PAGE_URL = `${BASE_URL}/ui-debug/components`;
|
||||
|
||||
async function main() {
|
||||
console.log("[task500] 启动 UI Debug 组件矩阵 smoke …");
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const context = await browser.newContext();
|
||||
const page = await context.newPage();
|
||||
|
||||
try {
|
||||
// 1. 认证
|
||||
await ensureAuthenticated(page);
|
||||
console.log("[task500] ✓ 已认证");
|
||||
|
||||
// 2. 导航到 /ui-debug/components
|
||||
await page.goto(PAGE_URL, { waitUntil: "networkidle", timeout: UI_TIMEOUT_MS });
|
||||
console.log("[task500] ✓ 页面已加载: %s", PAGE_URL);
|
||||
|
||||
// 3. 页面标题
|
||||
const title = await page.title();
|
||||
assert(title.includes("UI Debug"), `标题应包含 "UI Debug",实际: "${title}"`);
|
||||
console.log("[task500] ✓ 页面标题: %s", title);
|
||||
|
||||
// 4. 页面根元素
|
||||
const root = page.locator(".ui-debug-root");
|
||||
await root.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
console.log("[task500] ✓ .ui-debug-root 可见");
|
||||
|
||||
// 5. Button 矩阵应当可见
|
||||
const matrix = page.locator(".ui-debug-matrix");
|
||||
await matrix.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
const btnCount = await matrix.locator("button").count();
|
||||
assert(btnCount >= 12, `按钮矩阵应至少有 12 个按钮,实际: ${btnCount}`);
|
||||
console.log("[task500] ✓ 按钮矩阵: %d 个按钮", btnCount);
|
||||
|
||||
// 6. 主题切换
|
||||
const darkBtn = page.locator("[data-ui-debug-theme=\"dark\"]");
|
||||
await darkBtn.click();
|
||||
await page.waitForTimeout(200);
|
||||
const theme = await root.getAttribute("data-ui-debug-theme");
|
||||
assert(theme === "dark", `主题应为 dark,实际: "${theme}"`);
|
||||
console.log("[task500] ✓ 主题切换: dark");
|
||||
|
||||
// 切回 light
|
||||
const lightBtn = page.locator("[data-ui-debug-theme=\"light\"]");
|
||||
await lightBtn.click();
|
||||
await page.waitForTimeout(200);
|
||||
const theme2 = await root.getAttribute("data-ui-debug-theme");
|
||||
assert(theme2 === "light", `主题应为 light,实际: "${theme2}"`);
|
||||
|
||||
// 7. Dialog 对话框
|
||||
const dialogTrigger = page.locator("[data-ui-debug-dialog=\"info\"]");
|
||||
await dialogTrigger.click();
|
||||
await page.waitForTimeout(200);
|
||||
const dialogOverlay = page.locator("#ui-debug-dialog-overlay");
|
||||
const overlayVisible = await dialogOverlay.isVisible();
|
||||
assert(overlayVisible, "对话框应可见");
|
||||
const dialogTitle = await page.locator("#ui-debug-dialog-title").textContent();
|
||||
assert(dialogTitle.includes("提示"), `对话框标题应包含"提示",实际: "${dialogTitle}"`);
|
||||
console.log("[task500] ✓ 对话框打开: %s", dialogTitle);
|
||||
|
||||
// 关闭对话框
|
||||
const closeBtn = page.locator("[data-ui-debug-dialog-close=\"true\"]").first();
|
||||
await closeBtn.click();
|
||||
await page.waitForTimeout(200);
|
||||
const hidden = await dialogOverlay.getAttribute("hidden");
|
||||
assert(hidden !== null, "对话框应已关闭 (hidden)");
|
||||
console.log("[task500] ✓ 对话框已关闭");
|
||||
|
||||
// 8. Popover 菜单
|
||||
const popoverTrigger = page.locator("[data-ui-debug-popover=\"actions\"]");
|
||||
await popoverTrigger.click();
|
||||
await page.waitForTimeout(200);
|
||||
const popoverPanel = page.locator("[data-ui-debug-popover-panel=\"actions\"]");
|
||||
const popoverVisible = await popoverPanel.isVisible();
|
||||
assert(popoverVisible, "Popover 菜单应可见");
|
||||
const menuItems = await popoverPanel.locator("[role=\"menuitem\"]").count();
|
||||
assert(menuItems >= 2, `Popover 应至少有 2 个菜单项,实际: ${menuItems}`);
|
||||
console.log("[task500] ✓ Popover 打开: %d 个菜单项", menuItems);
|
||||
|
||||
// 关闭 popover
|
||||
await page.locator("body").click({ position: { x: 10, y: 10 } });
|
||||
await page.waitForTimeout(200);
|
||||
|
||||
// 9. Toast
|
||||
const toastTrigger = page.locator("[data-ui-debug-toast-kind=\"success\"]").first();
|
||||
await toastTrigger.click();
|
||||
await page.waitForTimeout(400);
|
||||
const toast = page.locator(".ui-debug-toast--visible");
|
||||
const toastCount = await toast.count();
|
||||
assert(toastCount >= 1, `Toast 应可见,实际数量: ${toastCount}`);
|
||||
console.log("[task500] ✓ Toast 显示");
|
||||
|
||||
// 10. Input / Select / Textarea
|
||||
const textInput = page.locator("#ui-debug-input-text");
|
||||
await textInput.waitFor({ state: "visible", timeout: UI_TIMEOUT_MS });
|
||||
await textInput.fill("测试文本");
|
||||
const inputValue = await textInput.inputValue();
|
||||
assert(inputValue === "测试文本", `输入框值应为"测试文本",实际: "${inputValue}"`);
|
||||
console.log("[task500] ✓ 文本输入: %s", inputValue);
|
||||
|
||||
const selectEl = page.locator("#ui-debug-select");
|
||||
await selectEl.selectOption("b");
|
||||
const selectValue = await selectEl.inputValue();
|
||||
assert(selectValue === "b", `下拉选择值应为"b",实际: "${selectValue}"`);
|
||||
console.log("[task500] ✓ 下拉选择: %s", selectValue);
|
||||
|
||||
const textarea = page.locator("#ui-debug-textarea");
|
||||
await textarea.fill("多行\n文本");
|
||||
const textareaValue = await textarea.inputValue();
|
||||
assert(textareaValue === "多行\n文本", `文本区域值应包含"多行",实际: "${textareaValue}"`);
|
||||
console.log("[task500] ✓ 文本区域: %s", textareaValue.replace(/\n/g, "\\n"));
|
||||
|
||||
// 11. CSS 变量检查
|
||||
const cssVar = await root.evaluate((el) => {
|
||||
const style = getComputedStyle(el);
|
||||
return style.getPropertyValue("--ui-debug-primary").trim();
|
||||
});
|
||||
assert(cssVar.length > 0, `--ui-debug-primary 应有值,实际: "${cssVar}"`);
|
||||
console.log("[task500] ✓ CSS 变量 --ui-debug-primary: %s", cssVar);
|
||||
|
||||
console.log("[task500] ✅ 全部断言通过");
|
||||
} catch (error) {
|
||||
console.error("[task500] ✗ 失败:", error.message);
|
||||
try {
|
||||
await page.screenshot({ path: "tmp/task500-failure.png", fullPage: true });
|
||||
console.log("[task500] 失败截图: tmp/task500-failure.png");
|
||||
} catch (_) {}
|
||||
process.exitCode = 1;
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user