
为什么e2e的act步骤可缓存而assert必须实时设计原理剖析【免费下载链接】e2eNext generation e2e testing framework for web and mobile apps.项目地址: https://gitcode.com/GitHub_Trending/e2e6/e2ee2e 是一个面向 Web 和移动应用的下一代端到端测试框架用自然语言描述目标AI 智能体agent就会驱动应用去完成它。在 e2e 中agent.act()步骤支持回放缓存——录制一次后后续运行零模型调用直接重放而agent.assert()则永远实时执行。这种不对称不是偶然而是深思熟虑的设计。本文带你从新手视角剖析其背后的原理。先搞清楚e2e 的两种 agent 步骤在 e2e 里一个测试通常长这样先让 agent 做事act再检查做对了没有assert / expect。agent.act()行动步骤驱动应用完成操作——点击、输入、导航。它会改变应用状态比如把工作区升级到 Pro 计划。agent.assert()断言步骤判断当前屏幕是否满足某条件比如发票预览显示按比例计费金额。它是只读的绝不能改变应用状态。这个一个动手、一个看结果的分工正是缓存设计差异的根源。e2e 的 act 步骤回放缓存是怎么工作的官方文档 docs/cache.mdx 描述的完整生命周期分四步录制首次运行时agent 用模型逐步操作应用每一步动作点了哪个控件、输入了什么值被记录成一条录制recording。确认act结束后不会立刻写盘。只有当后续的验证步骤通过如agent.assert或expect(...)断言录制才在尝试attempt结束时被正式写入.e2e/cache/目录。重放下次运行时框架按缓存条目重放动作——匹配路由、逐个找回控件并重复操作、再核对最终状态。全程零模型调用。自愈如果控件找不到、或最终状态没复现出来重放会中途移交hand-off给 agent从当前屏幕继续执行并自动重新录制。运行结束后报告里会看到类似这样的摘要AI 4.1k tokens · 2 model calls Cache 4 replayed · 1 handed off · 1 missed为什么只有 act 可缓存三条设计原理原理一assert 的本质是测量当下结果无法预先存储agent.assert回答的问题是此刻的屏幕上是不是出现了 X。答案完全取决于应用当下的状态——数据可能刚被修改、横幅可能刚弹出来、倒计时可能刚结束。如果把上次运行得到的通过结论缓存起来下次测试就会闭着眼通过断言根本没看一眼屏幕就宣称一切正常。那断言就失去了存在的意义。判断类步骤唯一正确的做法就是现在看、现在判。原理二assert 正是 act 录制的验收人这是最精妙的一点。e2e 的缓存写入有一个前提后续验证步骤必须通过。源码注释packages/e2e/src/agent/act.ts写得直白An assert is a verification step: its passing is what confirms the traces staged before it at attempt end.也就是说act的录制先被暂存staged要靠后面assert的实时通过来盖章确认才允许写入缓存。两条因果链在这里咬合assert的判定是act录制是否可信的依据如果assert的判定本身也能来自缓存那么一个过期的通过就会永远确认一条可能早已失效的录制——缓存变成自洽闭环错误永远无人发现。所以assert必须实时它是整个缓存体系的信任锚点。原理三assert 不改变状态本来就没有动作可录回放缓存的对象是动作序列点了什么、填了什么。而assert一个操作都不做它的动作轨迹天然为空——重放一段空轨迹毫无意义连查一次缓存都嫌浪费。源码在 packages/e2e/src/agent/act.ts 中直接写死了这个规则// Only act steps are cacheable: an assert must not change state, so its // trace would be empty — nothing to replay, nothing worth a read. const cache spec.kind act agent.executor.cache ! off ? runtime.cache : undefined;同理agent.waitFor和agent.extract也永远实时执行见 docs/cache.mdx 开头一句agent.assert、agent.waitFor和agent.extractalways run live。缓存的安全网应用变了会怎样既然缓存的是过去成功的操作序列应用一变怎么办e2e 的答案是宁可慢不可错路由不匹配wrong-context起点页面变了缓存不生效agent 从头执行。找不到控件target-not-foundUI 改版了等待 15 秒仍找不到则移交 agent下次通过的运行会重新录制。end-mismatch所有动作都重放成功但录制里应该出现的控件没出现——说明录制已不能产出预期效果。这条录制会被驱逐evict下次运行录一条干净的新流程。cache.strict模式已提交的录制失效时直接以REPLAY_STALE报错、拒绝静默重录强迫团队显式地重新录制并提交变更。所有缓存决策暂存、保留、驱逐都集中在 packages/e2e/src/agent/step-cache.ts 的StepTraceSession类中conclude()方法里的注释把什么情况下保留、什么情况下删除写得清清楚楚。新手最佳实践三步用好回放缓存每个act后面紧跟一次验证——agent.assert(...)或expect(screen.getByRole(...))。没有验证录制不会被确认缓存就永远建不起来。每次运行都变化的值时间戳、随机邮箱用unique()包裹这样重放时会自动替换为当前值不会因为数据不同而每次都缓存未命中。把.e2e/cache/提交进仓库共享重放CI 默认保持只读read-only本地开发用read-write负责重新录制。一个完整的示例项目可以直接参考examples/with-next/下面是它的运行截图。关键源码与文档路径想深入源码从这几个入口开始缓存核心按键派生、重放尝试、暂存/驱逐决策packages/e2e/src/agent/step-cache.ts步骤分发与只有 act 可缓存的闸门packages/e2e/src/agent/act.ts回放执行与终态校验packages/e2e/src/agent/replay.ts缓存官方文档重放细节、失效原因表、strict 模式docs/cache.mdxAgent 与多角色配置docs/agents.mdx总结一句话记住 e2e 缓存设计的核心逻辑act 改变世界所以它改变世界的方式可以被录制下来assert 审判世界而审判必须来自此刻。act 步骤可缓存是因为它是一段可重复的机械动作序列且录制经过了实时验证的盖章assert 必须实时是因为它的输出是对当下状态的判断——缓存一个判断就等于取消了判断本身。理解了这一点你就理解了 e2e 如何在不牺牲测试可信度的前提下把模型调用成本降到近乎为零。【免费下载链接】e2eNext generation e2e testing framework for web and mobile apps.项目地址: https://gitcode.com/GitHub_Trending/e2e6/e2e创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考