e2e Cache 性能指南:如何读懂 replayed、handed off、missed 三种缓存结果
【免费下载链接】e2eNext generation e2e testing framework for web and mobile apps.项目地址: https://gitcode.com/GitHub_Trending/e2e6/e2e
e2e 是一款面向 Web 和移动端的下一代端到端(e2e)测试框架,其中的 replay cache(回放缓存)能把 AI 智能体验证过的操作步骤自动重放,从而跳过昂贵的模型调用、大幅提升测试执行速度。本文带你完整解读运行总结里的三种缓存结果——replayed、handed off、missed 分别意味着什么,以及如何快速定位并排查缓存失效问题。
什么是 replay cache:先录后放,跳过模型调用
核心思路一句话:agent.act()步骤被模型成功执行并验证通过后,e2e 会把"点了什么、输入了什么、页面变成了什么样"录制下来;下次运行同一步骤时,直接回放这些操作,一次模型调用都不用发。
- 只有"有后续验证且验证通过"的步骤才会被写入缓存
agent.assert、agent.waitFor、agent.extract永远实时执行,不走缓存- 缓存条目是 JSON 文件,存放在项目的
.e2e/cache/目录下
一眼看懂运行总结:三种结果对照表
每次跑完测试,运行总结里都会有一行Cache统计,例如:
AI 4.1k tokens · 2 model calls · anthropic/claude-sonnet-4.5 Cache 4 replayed · 1 handed off · 1 missed| 运行总结 | step.cache.mode | 含义 | 通俗理解 |
|---|---|---|---|
replayed | self-finalized | 录制被完整回放,零模型调用 | 🏆 最理想:省时省钱 |
handed off | agent-concluded | 回放走了一半,AI 接手完成 | ⚠️ 部分命中:前缀回放,其余交给模型 |
missed | missed | 完全没回放,AI 从头执行 | 🐢 未命中:照常调用模型 |
missed 和 handed off 还会附带step.cache.reason,直接告诉你"为什么没回放成"——这是排查性能问题的第一入口。
replayed 是如何达成的
回放成功的条件并不只是"按钮还能找到",而是一整套四步验证:
- 起始屏幕相同:同一路由(记录 id、锚点差异可忽略),重试永不回放
- 控件全部找到:按角色、名称、test id 与上下文匹配,重复录制的动作
- 最终状态一致:最终路由、出现的控件、消失的控件、状态变化都要对得上
- 零模型调用收尾:全部校验通过才算 replayed
任何一个条件不满足,就降级为 handed off 或 missed。这套"决策—回放—校验—接管"的完整逻辑,核心实现在 step-cache.ts 中。
什么时候会 handed off
只要回放"已经开始执行动作"之后才发现问题,就算 handed off。对 AI 来说它拿到的是"已执行了什么、为什么停下"的完整记录,接着干即可。常见原因:
end-mismatch:动作都执行了,但录制的最终状态没有出现(上次运行留下的脏数据、飘忽的 banner,或真实回归)action-failed/action-uncertain:应用拒绝了回放的动作,或提交状态未知target-not-found/target-ambiguous:界面改版导致控件消失或出现歧义
什么时候会 missed
还没执行任何回放动作就停下来,就是 missed。高频原因速查:
| Reason | 发生了什么 | 怎么办 |
|---|---|---|
no-entry | 没有匹配的录制 | 无需处理,下次验证通过会自动录制 |
retry | 重试从不回放 | 无需处理 |
wrong-context | 起始屏幕和录制时不同 | 步骤前先打开同一屏幕 |
invalid-entry | 条目损坏或版本不符 | npx e2e cache clear |
truncated | 步骤超过 50 个动作等录制上限 | 拆分步骤,或改用Secret传参 |
完整原因清单见官方文档 docs/cache.mdx。
缓存命中靠什么匹配:避免每次都 missed
一条缓存条目绑定"特定测试 + 目标 + 指令 + 参数 + 智能体"。以下变化会直接导致 missed:
- 重命名测试或目标、修改指令或普通参数
- 换了一个配置的 agent,或修改了 agent 上下文(
agentContext) - 引擎升级了主版本或次版本
- ✅ 注意:更换模型不会导致 missed
两个新手高频坑:
- 时间戳 / 随机邮箱:每次运行值都不同 → 每次都 missed。用
unique()包裹这类值,回放时自动替换为当前值;会改变流程的选项(如套餐名)则保留为普通参数 - 预览环境 URL 每次部署都变:配置
app.identity保持缓存身份不变
缓存模式与 CI 性能最佳实践
| 模式 | 回放 | 录制 | 默认场景 |
|---|---|---|---|
read-write | ✅ | ✅ | 本地开发 |
read-only | ✅ | ❌ | CI(未显式配置时) |
off | ❌ | ❌ | --no-cache单次运行 |
针对 CI 性能的三条实战建议:
- 提交缓存目录:把
.e2e/cache/从.gitignore移除并提交,CI 才能享受回放红利;CI 保持read-only,重新录制在本地做(详见 docs/ci.mdx) - 严格模式防"静默失效":
--strict-cache(或cache: { strict: true })让"录制存在但回放不了"的步骤直接以REPLAY_STALE失败,而不是每次 CI 都默默烧掉模型调用 - 排除缓存嫌疑:怀疑缓存导致失败时,跑一次
npx e2e run --no-cache做对照
3 条命令掌握缓存全貌
npx e2e cache ls # 每个条目一行:测试、目标、指令摘要、年龄、动作数 npx e2e cache stats # 条目数量与总大小 npx e2e cache clear # 清空所有条目(遇到 invalid-entry 时先跑这个)推荐排查顺序:先看运行总结的Cache行 → 再看失败步骤的step.cache.reason→ 用cache ls确认条目是否存在、年龄多大 → 必要时用--no-cache或--strict-cache交叉验证。
延伸阅读
- 官方缓存文档:docs/cache.mdx
- CI 配置与缓存共享:docs/ci.mdx
- 缓存核心实现:packages/e2e/src/agent/step-cache.ts、packages/e2e/src/cache/store.ts
- 运行总结统计逻辑:format.ts
一句话总结:replayed 是省钱的胜利,handed off 是框架的保险丝,missed 是提醒你检查参数和界面。把step.cache.reason当成仪表盘,你的 e2e 测试速度会稳得超出预期。
【免费下载链接】e2eNext generation e2e testing framework for web and mobile apps.项目地址: https://gitcode.com/GitHub_Trending/e2e6/e2e
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考