用途
cdp-verification 用于通过 Chrome DevTools Protocol 驱动正在运行的桌面应用,端到端地验证 UI 行为。当被要求验证、复现或确认某个 UI 问题时,可使用该技能。它明确区分“有效证据”和“诊断辅助”:真实浏览器输入与可见 UI 导航才算端到端证明,直接赋值 DOM 属性、调用应用内部 API 或仅运行组件级脚本不能作为端到端行为的证明。
主要能力与验证规则
- 定位正确的应用实例:测试前确认并报告 worktree、renderer URL/端口和当前路由,并验证预期的已登录会话;另一个正在运行的桌面实例不等价。
- 复现精确的用户旅程:用户执行的步骤须使用真实浏览器输入和可见 UI 导航完成。
- 采集视觉与数值证据:截取操作前后截图,并配合相关 CDP 测量值(scrollTop、焦点元素、路由、持久化状态),确认截图与测量状态一致。
- 覆盖相关生命周期:包含报告中的实际路由切换、工作区/面板/文件切换、重新挂载或关闭后重开;更窄的合成流程不能替代。
- 不一致即视为复现不完整:若测试通过但用户仍观察到缺陷,需重新核对目标实例、具体步骤、输入方式、持久化键和生命周期时序;在改代码前先复现失败,合成冒烟测试不能否定用户报告。
- 证据门禁:对已报告缺陷或回归,须在相同观察条件下证明原始交互在修复前失败、修复后通过,才能声称验证完成;对新功能则记录等效的基线证据并展示预期行为。需清楚说明哪些检查是端到端的、哪些是合成的,以及截图是否实际捕获。
- 在真实布局中测试:不得为方便坐标而临时调整 UI 布局再据此泛化结论。布局相关失败恰恰存在于被“摆拍”设置移除的配置中:元素相距很远、有效目标之间的模糊区域、可滚动容器、折叠/空状态。若为搭建做过数据变更,还需在未摆拍的排列下重跑关键旅程。
- 对抗性驱动交互:对拖拽、缩放、滚动联动等连续交互,还要测试跨边界来回振荡、手势中途停留(0.5–1 秒)、触发自动滚动的长距离扫动、重复同一手势,以及人为制造主线程卡顿(如每 400ms 忙循环 120ms)以迫使事件批处理。留意交互自身状态变化重新触发其触发条件的反馈循环,并捕获 console.error(挂钩后断言为空):“Maximum update depth exceeded”和“Cannot update a component while rendering”即使截图正常也属于回归。
使用方式(Mechanics)
以下机制适用于 apps/desktop 中的 Electron 桌面应用。要针对真实 API/DB 端到端检查改动,可通过 CDP 驱动正在运行的开发应用。以未占用端口启动,例如 RENDERER_REMOTE_DEBUG_PORT=9222 bun dev(全栈;应用可能恢复已登录会话),然后通过页面目标的 webSocketDebuggerUrl 以 WebSocket 连接(Bun 内置,无需依赖)。示例脚本:apps/desktop/scripts/cdp-smoke-integrations.ts。
不要假设端口是 9222,也不要连接到其他工作区的 renderer。多个 Superset 工作区常同时运行,各自有不同的 renderer、API 和 CDP 端口。测试前:
- 从根目录 .env 读取本工作区的最终 DESKTOP_VITE_PORT 和 NEXT_PUBLIC_API_URL 值。
- 找到可执行文件/父命令路径位于本工作区内的 Electron 进程。其 renderer 命令行包含
--remote-debugging-port=<port>;可用lsof -nP -iTCP -sTCP:LISTEN确认所属 PID。 - 请求
http://127.0.0.1:<port>/json/list,要求存在 URL 使用本工作区 DESKTOP_VITE_PORT 的页面目标。仅 CDP 端点有响应不足以证明它属于当前分支。 - 使用脚本时显式传入匹配值,例如
RENDERER_REMOTE_DEBUG_PORT=<port> NEXT_PUBLIC_API_URL=<api-origin> bun run apps/desktop/scripts/cdp-smoke-integrations.ts。 - 测试前在匹配的 renderer 内验证
/api/auth/get-session。
修复 CDP 认证
先检查是哪个 setup 脚本供给了该工作区:
.superset/setup.local.sh创建每工作区本地栈并运行幂等的bun run db:seed-dev,但有意将登录留作单独步骤。若账户可能缺失,在本地 DB 栈运行时重跑bun run db:seed-dev。.superset/setup.sh在可用时从$HOME/.superset/auth-token.enc播种superset-dev-data/auth-token.enc。不带--force重跑可填补缺失 token。不要仅为修复认证而使用--force:它会重置superset-dev-data/再重新播种。
桌面应用会将持久化 token 水合到内存中的 bearer-token 闭包。原始 Runtime.evaluate fetch 读不到该闭包,本地开发登录按钮虽持久化 bearer token 但使用 credentials: "omit",二者都不能保证原始 CDP 探测所需的 cookie。对于由 setup.local.sh 创建的工作区,按以下方式修复 CDP 会话:
- 要求 localhost API 源;绝不向远程或共享 API 发送开发凭据。
- 在 apps/desktop 下(以便工作区导入可解析)从
@superset/shared/dev-credentials导入 DEV_EMAIL 和 DEV_PASSWORD;不要把字面值复制到脚本或日志。 - 在匹配的 renderer 中通过 Runtime.evaluate,以 JSON content type 和
credentials: "include"向${NEXT_PUBLIC_API_URL}/api/auth/sign-in/emailPOST 这些凭据。不要打印返回的 token 或响应体。 - 以
credentials: "include"重新请求/api/auth/get-session,在运行测试前要求 session 和 session.activeOrganizationId 同时存在。
这种带凭据的本地开发登录会创建后续 renderer 内请求所需的浏览器会话 cookie。若失败,只报告登录/会话状态码。非本地设置请使用应用正常登录流程,绝不替换为本地开发凭据。
对于非本地工作区,正常桌面流程会有意将加密 bearer token 恢复到 renderer 内存中的 auth client,而不会创建浏览器 cookie。若 renderer 处于已认证路由但仅 cookie 探测返回无会话,可用 Runtime.evaluate 从 renderer 开发服务器导入 /lib/auth-client.ts 并调用 authClient.getSession({ fetchOptions: { throw: false } })。这仍通过应用真实认证请求路径验证 /api/auth/get-session。只返回状态和 session.activeOrganizationId;绝不调用或打印 getAuthToken()。
不要用 setup --force 修复过时连接字符串、缺失 CDP cookie 或损坏的生成 Next.js 缓存。先不带 force 重跑适用的 setup 脚本。若所有 API 路由都返回 Next.js 的 HTML 404,停止开发栈,将 apps/api/.next 移开并重启。--force 通常仅在用户明确打算替换复制的本地/宿主数据库和加密认证 token 时才合适。资料记录了一个例外失败特征(验证于 2026-07-28):会话恢复卡在“Restoring your session”、Local Admin 登录按钮返回无响应体 500、get-session 返回 200、对 DATABASE_URL 原始 select 1 可能仍成功,此时工作区播种的开发状态(.env 中的 Neon 分支凭据、auth-token.enc、复制的 DB)作为一个集合已过期;带 --force 重跑会重建 Neon 分支、重写 .env 并重新播种 superset-dev-data/,从而恢复登录。需预期两个副作用:手动 .env 编辑(如端口重映射)会被清除需重新应用,且 superset-dev-data/ 会被重置。
使用 Runtime.evaluate(awaitPromise、returnByValue),不要用 Network.* 拦截;嗅探会漏掉 React-Query 缓存响应,且 fetchInterval 在窗口后台时会暂停。在通过上述 cookie 或 bearer 路径验证会话后,在 renderer 内运行请求。API 为开发后端源(NEXT_PUBLIC_API_URL,例如 http://localhost:5881):
- 活动组织:本地 cookie 流程使用
fetch(API + "/api/auth/get-session", {credentials:"include"});非本地 bearer 流程使用authClient.getSession({ fetchOptions: { throw: false } })。要求存在 .session.activeOrganizationId。 - tRPC 查询(绕过缓存):
GET API + "/api/trpc/<proc>?batch=1&input=" + encodeURIComponent(JSON.stringify({"0":{json:<input>}}));响应为[{result:{data:{json:...}}}]。 window.location.hash导航可能不会重新挂载路由;应直接调用端点。
适用场景
用于 Electron 桌面应用的 UI 行为验证、缺陷复现与回归确认,尤其是拖拽、滚动联动、布局相关交互等容易在合成测试中漏过的问题;也用于建立新功能的基线证据。
限制
资料给出的机制说明专门针对 apps/desktop 中的 Electron 桌面应用和 Superset 工作区的本地开发环境;未提供其他平台、其他框架或生产环境的适用说明。技能本身未描述图形界面操作入口或安装方式,具体使用需依托上述脚本与命令。