返回 Skill 列表
extension
分类: 开发与工程无需 API Key

智能体UI设计与验证技能(配套NEXENT集成技能)

基于智能体场景,结合思考过程动作摘要、流式输出设计、滚动三态等元素指导UI设计。验证阶段用 puppeteer-core“真实打开浏览器页面”,复现并验证前端 UI 问题的技能,覆盖通用 UI bug 与 SSE 流式前端呈现验证。

person作者: dmkx01hubModelScope

UI 浏览器测试

Overview

用 puppeteer-core 启动本机 Chrome 无头浏览器,真实打开页面复现 UI 问题。不依赖用户描述猜测根因,而是捕获真实请求/响应/控制台/DOM 数据后定位问题,修复后同一脚本复测验证。

目录

关键前提

  1. 需要 puppeteer-core(在 node_modules 中)和本机 Chrome:
    • Chrome 路径:优先用环境变量 CHROME_PATH 指定;未设置时按平台默认查找 (Windows C:/Program Files/Google/Chrome/Application/chrome.exeProgram Files (x86) 下同名路径; macOS /Applications/Google Chrome.app/Contents/MacOS/Google Chrome;Linux /usr/bin/google-chrome
    • 运行需设置:NODE_PATH=<node_modules路径>
  2. 本地开发服务需已启动(如 uvicorn)。
  3. 页面有登录时需提供测试账号。

工作流程

Step 1: 用模板脚本快速复现

scripts/ui_test.js 是通用模板,覆盖核心捕获能力(console/pageerror、API 请求体与响应、DOM 快照、截图):

# 基础: 打开页面, 等待 5s, 截图(<url> 换成你的本地服务地址)
NODE_PATH=.../node_modules node ui_test.js <url> --wait-ms 5000

# 带登录(凭据用测试账号,可通过参数传入)
node ui_test.js <url> --login-user <user@example.com> --login-pass <password>

# 登录后点击某个按钮, 捕获指定 API 的请求/响应, 等待 8s
# (--click-selector / --watch-api 按目标系统实际元素与接口替换)
node ui_test.js <url> \
  --login-user <user@example.com> --login-pass <password> \
  --click-selector "<打开弹窗的按钮选择器>" \
  --watch-api "<要监听的接口路径片段>" \
  --wait-ms 8000

模板会输出:[REQ-BODY](重点看 postData 是否为空!)、[RESP] 状态码、DOM 快照(tables/modals/是否含 [object Object])、截图路径、控制台错误。

Step 2: 分析捕获数据定位根因

对照 references/bug-patterns.md 常见问题速查表:

| 现象 | 排查方向 | |---|---| | [object Object] | 看 [RESP] 状态码;若 422 → 抓 [REQ-BODY] 是否空 → 对象展开丢键 / new Error(数组) | | 排版错乱/TBLSEP | 用 Node 单独跑渲染函数 + 真实 LLM 输出断言 | | 流式闪现 | 检查 SSE 事件粒度,thinking 只显示动画 | | 部署未生效 | md5 对比 + HTTP 抓取 + 服务重启(Python 必须重启进程)| | 数据偶尔丢失/消失 | 持久化类 bug(§12)grep localStorage 全部读写点 → 判定单例还是实体集合 → 序列推演(A存→B存→A读)→ 无 clear/removeItem 即非"被清掉",而是单键互斥覆盖 |

Step 3: 修复 + 同一脚本复测

  • 修复代码后重跑同一测试脚本,确认:
    • [REQ-BODY] 非空
    • DOM 快照断言通过(无 [object Object]、table 数量正确)
    • 无 console/pageerror
  • 截图人工确认视觉效果(保存于 ui-shots/
  • 修复后必做举一反三(§11):同类问题是否在代码其他位置/场景同样存在(同函数不同分支、同模式不同位置、同数据不同入口、同 UI 不同视图),一并修复或列待办

Step 4: 强断言检查清单(防假阳性)

测试通过 ≠ 功能正确。三类陷阱(详见 references/bug-patterns.md §8、§9、§10):

第一类(元素层)

  1. className ≠ 布局:断言 offsetWidth/Height 真实尺寸,不只断言 className
  2. innerText ≠ DOM 结构:断言 querySelectorAll("table").length >= 1,不只断言"innerText 包含"
  3. 测试场景 ≠ 真实路径:用"实际传递给被测代码"的输入(如 slice(0,8) 截断后的文本),不只测完整数据

第二类(体验层,更隐蔽): 4. 只测最终态漏测过程态:流式/异步/动画功能必须多次采样断言渐进变化(15s × 6),不能只等 100s 测最终 5. 元素存在 ≠ 用户看得到:断言 scrollHeight <= clientHeight(无 overflow 裁剪),关键结论在视口内 6. 弹性布局只测单点:用长/短两种内容量各测一遍,断言折叠/展开行为 7. 前后端契约不同步:改后端提示词后必须用真实输出全链路验证,断言新小节映射生效

第三类(滚动/交互层): 8. 嵌套滚动容器错位:监听、赋值、测试必须都指向真正可滚动的元素(CSS 有 overflow-y:auto 且内容溢出);外层 overflow:hidden 的 scrollTop 恒为 0,赋值无效 9. 测试操作了错误的元素:若被测元素 scrollTop 恒 0,任何"保持 0"断言都是假阳性——断言前先验证 scrollHeight > clientHeight(元素确实可滚动、内容确实溢出) 10. 滚动三态:自动跟随 / 手动滚动后不拉回 / 滚回底部恢复跟随,三态都要测

通用铁律:断言目标必须是用户实际感知的体验(看、点、读、确认结果),而非"代码做了什么"。

修复后必须逐项检查:

| 类型 | 弱断言陷阱 | 强断言方式 | |---|---|---| | 布局/尺寸 | className.includes("...") | offsetWidth/Height ≈ window.innerWidth/Height | | 结构渲染 | innerText.includes("...") | querySelectorAll("table").length >= N | | 截断边界 | 用完整输入测 | 用真实截断数据测(slice/cutoff) | | 过程态 | 只测最终态 | 流式/异步多次采样断言渐进增长 | | 可见性 | 元素存在 | scrollHeight <= clientHeight 无裁剪 | | 弹性布局 | 单点内容量 | 长/短内容各测,断言折叠/展开 | | 前后端契约 | 固定 mock 数据 | 真实后端输出全链路,断言新映射生效 | | 嵌套滚动 | 操作外层容器 | 监听/赋值/测试指向同一可滚动元素,先验证 scrollHeight > clientHeight | | 滚动三态 | 只测"保持 0" | 自动跟随 / 手动不拉回 / 回底恢复 三态全测 | | 图表初始化时机 | 只查 DOM 存在 | 渲染元素实际宽度 = 容器宽度(防隐藏容器内 init 退化为默认尺寸,如 ECharts 100px) | | 可点击 | el 存在 | getBoundingClientRect() 在视口内 | | 网络成功 | resp.ok | 同时检查 Content-Type 和可解析 body |

专项测试场景

场景 A: 弹窗/模态框

node ui_test.js <url> --login-user U --login-pass P \
  --click-selector "#btn-open-modal" --wait-ms 3000
# 断言: modals >= 1, 弹窗内无 [object Object], 截图

场景 B: SSE 流式渲染(AI 对话等)

node ui_test.js <url> --login-user U --login-pass P \
  --click-selector "<触发流式的按钮>" --watch-api "<流式接口路径片段>" --wait-ms 100000
# 断言: REQ-BODY 非空(关键!); 完成后表格数>0; 无 TBLSEP/###/[object Object]
# 注: 流式接口响应体无法用 resp.text() 读取(已消费), 依赖截图+DOM 验证

场景 C: 页面功能回归(列表/表单/跳转)

node ui_test.js <url> --click-selector "nav a" --click-selector "#search-input" --wait-ms 3000

自定义测试脚本

模板不满足时(如需要多步交互、断言特定 DOM),直接写一次性 puppeteer 脚本(参考 scripts/ui_test.js 结构):

  1. page.on('pageerror') + page.on('console') 收集错误
  2. page.on('request'/'response') 按 URL 片段过滤捕获 API
  3. page.evaluate() 执行交互与 DOM 断言
  4. page.screenshot() 保存证据
  5. 输出结构化结果(JSON 格式便于解析)

关键 API 速记:

  • page.type(sel, text) 输入
  • page.click(sel) / page.evaluate(s => document.querySelector(s).click()) 点击
  • page.$eval(sel, el => el.outerHTML) 抓 HTML
  • page.evaluate(() => document.body.innerText) 抓文本
  • page.screenshot({path}) 截图

Resources

  • scripts/ui_test.js — 通用测试模板(登录/点击/API 捕获/DOM 断言/截图,命令行参数化)
  • references/streaming-ui.mdSSE 流式输出前端呈现与验证(三层呈现架构 + 打字机 / 智能滚动三态 / 关闭弹窗不中断与重开恢复(DOM 解耦)/ 图表容器可见后初始化 / 真实浏览器渲染验证铁律 / 验证清单;本文件只覆盖"流到了前端怎么渲染、怎么验证",接口/协议层(事件类型、会话 id、请求体构造)见你所对接平台的集成技能或接口文档;已按去项目化规则泛化,供对接任意 SSE 流式接口复用)
  • references/bug-patterns.md — UI 常见问题根因速查 + 反思沉淀(§1-7 速查:[object Object]/TBLSEP/###/流式闪现/部署未生效/排查命令/方法论核心;§8-12 反思:三类假阳性、四类隐蔽假阳性、嵌套滚动容器错位、举一反三同类排查持久化类 bug 单键互斥覆盖§13 图表隐藏容器内 init 退化为默认尺寸(与 streaming-ui.md §4 同源)
  • references/90-qc-ground-truth.md【质控专用,非使用教程】:领域事实清单/复查清单(15 条核心结论 + 已发现问题记录),本技能逻辑复查的领域锚点;质控方法论详见独立技能 skill-qc(L0~L4),质控时加载 skill-qc 执行;正常使用本技能无需阅读,仅在排查/修订/复查时对照使用