回演想解决的,其实不是「写脚本」
做回演(CueCast)时,我一直想解决的不是「让大家少写几行测试脚本」,而是让测试人员或业务人员在真实业务页面里录下操作,再把它沉淀成可治理、可回放、可追溯的测试资产。
一句话概括:用 Chrome 扩展采集真实操作,用中台治理步骤和结果,用 CDP + DOM 双引擎完成稳定回放,并用 AI 辅助处理复杂步骤与失败分析。
先看一下整个系统怎么拼起来
2.1 仓库结构
| 模块 | 技术栈 | 主要职责 |
|---|---|---|
extension/ |
Chrome Extension Manifest V3 | 录制、回放执行、CDP 调用、截图,以及与页面脚本通信。 |
backend/ |
Node.js + Express + MySQL | 用户、项目、用例、步骤、结果 API;AI 规划和失败分析。 |
frontend/ |
Vue 3 + Vite | 用例治理、步骤编辑、计划执行、结果报告与工作台。 |
marketing/ |
Vite + Tailwind | 官网与对外产品叙事。 |
ops/ |
Shell + Docker Compose | 部署与升级脚本。 |
2.2 整体架构
用户通过 Vue 3 管理中台治理用例;Chrome MV3 扩展负责与目标业务系统交互,并由 Content Script 与 CDP 承担录制、回放两条路径。后端 API 统一连接 MySQL 与 OpenAI-compatible 的模型服务。

录制:不要只留一个脆弱的选择器
录制入口在 Chrome 扩展后台的 RecorderManager,页面内采集逻辑位于 extension/content/recorder.js。
3.1 录制流程
1 | 用户在业务页面操作 |
3.2 稳定定位:不只保存一个选择器
早期录制回放最常见的问题是「选择器漂移」:动态 ID、组件库重渲染、表格行变化、弹窗层级变化,都会让单一 CSS 或 XPath 很快失效。
当前录制侧会同时保存多类定位资产:
| 字段 | 用途 |
|---|---|
target_selector |
主 CSS 定位。 |
target_xpath |
XPath 兜底,尤其适合表格行列、浮层文本。 |
locator_meta |
智能定位元信息,包含多个候选定位器和上下文评分信息。 |
value |
输入值、下拉选项文本、断言文本等。 |
screenshot / screenshot_focus |
步骤截图和焦点区域,用于治理与排障。 |
locator_meta 是稳定性核心之一。它会记录多个候选定位器,例如:
data-testid、data-test、name、aria-label、placeholder、title、role;- 稳定 ID,但会过滤
rc_*、ReactuseId、长 Hash、纯数字等易变 ID; - 组件根节点 Class,例如 Ant / iView / Element Select;
- 用于按钮、链接、菜单项的文本精确匹配候选;
- XPath Fallback。
同时还会记录上下文信息:
| 上下文 | 解决的问题 |
|---|---|
control_kind |
区分 input、textarea、combobox、button、link。 |
label_text |
表单项重排后仍可按标签找回控件。 |
container_text |
在表格行、表单块、映射行等场景中进行语义匹配。 |
sibling_index |
同类控件重复时,以兄弟序号辅助定位。 |
rect |
位置变化不大时,以视口相对位置辅助评分。 |
reveal |
记录「先 hover/click 触发,再点击浮层项」的依赖关系。 |
3.3 组件库专项处理
当前代码对常见组件库做了专项稳定性优化:
| 场景 | 处理策略 |
|---|---|
Ant Design / rc-select 动态 ID |
过滤 rc_*,改用组件根节点、表格行列或可见搜索框兜底。 |
| iView / Element / Ant 下拉浮层 | 浮层项保存文本 XPath 和 value,不依赖 body 下临时 DOM 路径。 |
| 表格 Checkbox | 按 tbody / thead 内行号定位,避免表头和表体混算。 |
| iView Table 单元格图标 | 先用 tbody/tr[n]/td[m] 重定位单元格,再找链接、图标或单元格。 |
| Radio / Checkbox 的 0 尺寸原生 Input | 视觉截图和点击目标提升到外层 label / wrapper。 |
| Hover 展开菜单 | 只录制严格的菜单触发器,并为后续点击绑定 reveal 关系。 |
3.4 录制去噪
录制不是把所有事件原样保存,而是会做去噪和治理:
- 连续输入同一目标时,只保留最后一个
input步骤; radio/checkbox的极短时间重复click会去重;- 普通
hover不会随意录制,只保留能展开菜单或下拉框的严格触发器; - 支持从某一步后插入录制:开始前拉取已有步骤快照,停止时再合并保存;
- 录制标签页异常关闭时,尽力保存已录步骤。
3.5 高级步骤治理能力
录制只是起点。真正让用例长期可维护的是中台的步骤治理能力:录制出来的步骤是可编辑资产,而不是一次性脚本。
| 能力 | 价值 |
|---|---|
| 步骤拖拽排序 | 录制顺序不理想时,可以直接拖动步骤卡片重新排序;保存后整体覆盖步骤顺序。 |
| 步骤复制与粘贴 | 支持单步或多步复制,可粘贴到当前用例末尾或指定位置;剪贴板保存在本地,不同用例之间也可复用公共流程片段。 |
| 批量操作 | 支持批量选择、复制、删除和清空步骤,便于清理无效录制片段或复用连续业务流程。 |
| 撤销上一次步骤变更 | 对排序、粘贴、删除等整表保存操作保留撤销空间,降低误操作成本。 |
| 从步骤间继续录制 | 可在两步之间发起录制,新录到的步骤会合并进原用例中间。 |
| 插入智能步骤 | 可在任意步骤后插入 ai_natural;若自然语言写成 1. ...、2. ... 等编号指令,保存时可自动拆成多条 AI 步骤。 |
回放:尽量还原真实用户的操作
回放入口在 extension/modules/player-manager.js,有两条执行路径:
- CDP 主路径:通过
chrome.debugger调用 Chrome DevTools Protocol,模拟真实鼠标、键盘并截图。 - DOM 降级路径:页面内的
content/player.js通过 DOM API 触发事件。
4.1 为什么选择 CDP 主路径
在复杂前端页面中,DOM 的 element.click() 并不等价于真实用户操作。受控输入、浮层、遮罩、Hover、命中测试、键盘确认等场景都更接近浏览器底层输入模型。
CDP 主路径可以:
- 通过
Input.dispatchMouseEvent发送mouseMoved、mousePressed、mouseReleased; - 通过
Input.dispatchKeyEvent发送真实键盘事件; - 执行 Hit Test,判断中心点是否被遮罩或弹窗遮挡;
- 使用
Page.captureScreenshot记录每一步截图; - 在后台直接执行断言,避免
tabs.sendMessage回包丢失导致失败被当成成功。
4.2 CDP 与 DOM 降级的使用边界
当前策略是:**CDP 是主路径,DOM 降级是保底路径。**能用 CDP 时优先使用它,因为它更接近真实用户操作;仅当 CDP 不可用或部分场景受限时,才退回到页面内的 DOM 执行。
| 场景 | 使用策略 | 原因 |
|---|---|---|
| 普通点击 / 输入 / 按键 / 滚动 / 悬浮 | 优先 CDP,CDP 不可用时走 DOM 降级 | CDP 可模拟鼠标、键盘并做遮挡检测;DOM 用于兜底。 |
文本断言 assert_text |
优先 CDP,CDP 不可用时走 DOM 降级 | CDP 后台直接断言更可靠;DOM 路径兼容普通页面文本检查。 |
JSON 断言 assert_json |
必须 CDP | 需要后台稳定读取目标元素原始文本,再提交后端做 JSON 语义比对。 |
智能自然语言步骤 ai_natural |
必须 CDP | 需要采集页面结构、打节点标记,并由 CDP 执行模型规划后的动作。 |
| CDP Attach 失败、跨扩展页面受限 | 尝试 DOM 降级 | 让普通步骤仍有机会执行,提高回放链路可用性。 |
| 浏览器内置页、其他扩展页、不可注入页面 | 直接失败或提示修改 URL | 这类页面既无法稳定注入脚本,也无法正常执行回放。 |
因此,DOM 降级并非替代 CDP,而是在主路径不可用时,为普通步骤保留的一条兜底执行链路。
4.3 回放主流程
下图展示了从读取用例、打开目标页、Attach CDP,到按步骤类型分流执行、保存结果和清理现场的完整链路:

4.4 元素查找策略
回放侧的定位顺序并不是简单的 querySelector。以 CDP 路径为例,核心策略包括:

- XPath 出现多匹配时,不使用
FIRST_ORDERED_NODE,而是在 Snapshot 后按可见性、弹窗和z-index选择; - CSS 多匹配时按上下文评分,不直接拿第一个元素;
- 对弹窗内的「确定」等重复文案,优先选择当前可见弹窗内、堆叠层级最高的节点;
- 对 Ant Select 搜索框,CSS 多匹配时会结合表格 XPath 行列提示定位;
- 点击前重新获取坐标,减少滚动后布局变化导致的偏差。
4.5 等待策略
稳定回放不能只靠固定 sleep。当前实现有三层等待:
| 等待类型 | 策略 |
|---|---|
| 标签页加载 | 打开页面后轮询 tab.status === complete。 |
| 元素等待 | 每 400ms 轮询,默认 5–10 秒超时。 |
| 全页 Loading | 检测 iView / Ant / Element / aria-busy 等 Loading UI。 |
全页 Loading 有 180 秒上限,避免接口一直 Loading 时无限等待。
4.6 页面错误快速失败
回放每步前都会检查页面错误信号:
- 常见错误文案:请求失败、加载失败、网络错误、权限不足、
Internal Server Error、Bad Gateway、Gateway Timeout等; - 常见错误组件:iView / Element / Ant / Arco 的
message、alert、notice等。
一旦命中,回放会中止并保存失败原因,而不是继续执行后续步骤制造误导性错误。
4.7 断言策略
目前支持两类重点断言:
| 断言类型 | 策略 |
|---|---|
assert_text |
有定位器时读取目标元素原文:input / textarea 取 value,其他取 textContent 并全等比对;无定位器时兼容旧行为,判断整页 innerText 是否包含预期文本。 |
assert_json |
通过 CDP 采集目标容器原始文本,提交后端与步骤中保存的 JSON 原文比较。 |
断言失败不会触发 AI 失败分析,以免把「预期不一致」这个明确结论再泛化成不确定诊断。
我们最终采用的回放策略
5.1 策略总览
整体回放策略可以概括为:
- 执行前做基础检查:判断是否被用户停止、是否命中页面错误提示、是否需要执行
wait_before。 - 判断步骤是否必须 CDP:
ai_natural和assert_json必须走 CDP;CDP 不可用时直接失败。 - 普通交互优先使用 CDP:
click、input、key、scroll、hover等通过 CDP 模拟真实鼠标和键盘。 - 普通断言优先使用 CDP:
assert_text优先在后台直接断言,避免消息回包丢失。 - CDP 不可用时尝试 DOM 降级:普通交互和普通文本断言退回
content/player.js执行。 - 每步成功后进行稳定性收尾:必要时等待页面加载完成,并记录回放截图。
- 一旦失败立即沉淀现场:保存失败步骤、错误信息、截图、DOM 摘要、页面正文和资源请求提示,供报告与 AI 分析使用。
5.2 失败结果沉淀
失败现场包含当前 URL、标题、DOM 摘要、正文文本摘要、最近资源请求提示等。这为后续的报告、排障和 AI 诊断提供完整上下文。
AI 在这里做什么,不做什么
当前 AI 不会替代录制资产,而是用于增强复杂场景。
6.1 自然语言智能步骤
ai_natural 步骤的执行流程:
- 采集页面结构:扩展通过 CDP 采集当前页面的可交互节点,包括按钮、输入框、下拉选项、表格复选框等。
- 提交模型规划:后端将自然语言指令和页面结构提交给大模型,让它返回受控的
operations。 - 本地执行操作:扩展不让模型直接操作页面,而是按模型返回的
nodeId和action,用本地 CDP 引擎执行点击、输入、悬浮、勾选、断言等动作。AI 只负责「规划」,最终执行仍由本地 CDP 引擎完成。 - 处理 DOM 变化:若多步操作之间页面重渲染,会重新采集页面结构,并根据文本、行上下文、控件类型等把旧
nodeId映射到新节点。
可交互节点的采集重点包括:
- 主页面按钮、链接、输入框、树节点、表格行、复选框;
- 已展开下拉浮层中的选项;
- 表格 Checkbox 的
row_context,用于解决「复选框本身没有文本」的问题; checked状态,支持check/uncheck的幂等执行。
使用场景之一:创建 CC 任务时可由自然语言步骤完成任意选表。
6.2 AI 失败分析
当普通回放失败且后端配置了 AI API 时,后端会将失败现场 JSON 发送给模型,生成简短的中文失败原因(可选)。
设计约束:
- 最多 280 字;
- 只解释失败现场与可能根因;
- 不输出修复步骤,避免报告混入不可靠建议;
- 断言失败不做 AI 分析,因为断言本身已经是明确结果。
后面想继续尝试的 AI 能力
| 方向 | 设想 |
|---|---|
| 步骤自修复 | 回放失败时基于旧 Locator、截图、DOM 差异生成候选新定位器,人工确认后写回。 |
| 稳定性评分 | 为每个步骤计算 Locator 稳定性分,提示动态 ID、弱 XPath、重复文本等风险。 |
| 录制后优化 | 录制完成后自动合并冗余步骤、补充描述、识别关键断言建议。 |
| 用例影响分析 | 页面结构或版本变化后,预测哪些用例可能受影响。 |
| 补充缺失用例 | 分析当前用例资源,建议并自动补充缺失或边界用例。 |
| 失败聚类 | 按错误文案、失败步骤、DOM 摘要、接口提示对失败结果聚类,减少重复排障。 |
这套方案最后留下的五层防线
回演当前的稳定性设计可以总结为五层防线:

| 防线 | 做法 |
|---|---|
| 录制 | 多维定位资产、上下文和截图,而不是只保存单个选择器。 |
| 定位 | CSS、XPath、文本、组件根节点和上下文评分共同决策。 |
| 执行 | CDP 优先模拟真实交互,DOM 路径作为普通步骤的兜底。 |
| 等待 | 标签页、元素与全页 Loading 分层等待,并设置超时上限。 |
| 诊断 | 快速失败并保留截图、DOM 摘要、正文与资源提示,供排障和 AI 分析。 |
这套设计的关键思想是:不要把稳定性押在某一个选择器上,而是在录制、定位、执行、等待、诊断的每一层都留出容错空间。
还没做完的事
- 文档和产品宣发;
- 工程稳定性和架构优化;
- 内部建立测试用例库,在使用中持续验证;
- 继续参考 Testim 的录制回放策略,取其精华、去其糟粕;
- 支持私有部署模式;
- 支持项目协作,参考语雀的简单权限模式;
- 支持接入 CI/CD;
- 支持导入、导出测试脚本,以承接已有的测试用例资产。