引言“Describe a goal in natural language and an agent drives the app to reach it. Check the result with locators and assertions in the same test.”这是「每日一个开源项目」系列的第 229 篇。今天的项目是e2e—— TesterArmy 出品的 Web 和移动端端到端测试框架6,361 颗 StarApache-2.0 许可证。端到端测试这件事长期卡在一个矛盾里写死的选择器selector一旦 UI 改版就全线崩溃但如果测试逻辑太模糊又没法可靠地跑在 CI 里。e2e 的答案是把测试拆成三种性质完全不同的步骤——用自然语言描述的 Agent 操作Goal、用模型判断的断言Assertion、用精确选择器写的验证Locator——然后用一套回放缓存机制让验证过的 Agent 操作可以在后续运行里完全跳过模型调用只有当应用真的变化时才重新唤醒 Agent。你会学到什么三种测试步骤的分工Goal / Assertion / Locator回放缓存Replay Cache如何让 AI 驱动的测试摆脱每次都要调模型的成本问题Decision Model 执行器用小模型做选择题而不是让大模型自由发挥快速上手npx e2e init到写第一个测试从 Playwright / Cypress / Detox / Maestro 迁移的路径前提知识写过 Playwright、Cypress 或类似的端到端测试了解 LLM Agent 的基本工作方式指令 → 观察 → 操作循环TypeScript 基础使用经验项目背景概述e2e 由 TesterArmy 开发——这家公司本身做的是在每次 PR 或按计划在 Web/移动应用上跑自然语言测试的 Agentic 测试平台。e2e 是这套能力的开源核心引擎。它不是又一个让 AI 帮你生成测试代码的工具而是把AI 驱动的操作本身嵌入测试运行时一个测试里哪些步骤该让 Agent 自己判断怎么点、哪些步骤必须用精确选择器锁死由开发者显式分工。项目信息组织: TesterArmy主要语言: TypeScript许可证: Apache-2.0创建时间: 2026-07-22当前状态: 朝 1.0 迈进API 和配置仍可能在小版本间变化项目数据⭐ GitHub Stars:6,361 Forks: 285 许可证: Apache-2.0 创建时间: 2026-07-22️ Topics: e2e, e2e-testing, end-to-end-testing, mobile, mobile-testing, playwright, web快速上手安装npx e2e initinit会询问引擎类型Web 或移动端和模型提供商然后生成配置文件和一个示例测试。写一个测试// tests/checkout.e2e.tsimport{test,expect}frome2e;test(a member upgrades to Pro,async({app,agent,screen}){awaitapp.open(/settings/billing);awaitagent.act(upgrade the workspace to the Pro plan);awaitagent.assert(the invoice preview shows a prorated amount);awaitexpect(screen.getByRole(status)).toContainText(Pro);});这个测试里三种步骤同时出现agent.act让 Agent 自己完成升级到 Pro这个目标agent.assert让模型判断发票预览的语义是否正确expect用精确的 role 选择器验证最终状态。支持的引擎包作用e2eSDK、runner 和 CLIe2e-dev/web浏览器引擎通过 Playwright 驱动 Chromium、Firefox、WebKite2e-dev/mobileiOS/Android 引擎通过 agent-device 驱动模拟器/真机e2e-dev/github把测试结果作为 PR 评论发布的 Reportere2e-dev/kernelKernel 托管的云端浏览器e2e-dev/easEAS Simulators 托管的 iOS/Android 模拟器e2e-dev/decision用 Decision Model而非完整 LLM执行语义化动作和断言官方提供 Vite、Next.js、Expo、SwiftUI 四种技术栈的完整示例项目。核心三种步骤的分工e2e 把测试步骤划分为三类各自有不同的模型调用策略步骤API是否调模型Goal目标agent.act是除非被缓存重放Assertion断言agent.assert/agent.waitFor/agent.extract是Locator定位器screen和expect否Goal让 Agent 自己走流程awaitagent.act(complete checkout with the test card);awaitagent.act(invite {email} as an editor,{params:{email:adaexample.test}});agent.act只接受一个目标描述Agent 自己决定点哪里、输入什么。开发者控制的是目标之间的顺序不控制目标内部的执行细节。官方给出的实践建议每次调用只写一个目标用屏幕上实际出现的文案描述测试数据放进params密码类数据用Secret模型看不到明文每次运行会变化的值如邮箱、时间戳用unique()包裹这样回放缓存才能正确匹配Assertion模型判断语义是否成立awaitagent.assert(the dashboard shows a trial badge);awaitagent.waitFor(a download link appears,{timeout:120_000});constdataawaitagent.extract(every todo title,{schema:z.object({titles:z.array(z.string())}),});断言模型只看当前屏幕的文本快照和 Agent 的 context不看之前步骤的历史或摘要——这是故意的隔离设计避免断言被前面步骤的叙事带偏。对于需要视觉判断的场景图表、布局可以加vision: true让模型看截图。Locator精确场景不走模型awaitscreen.getByRole(button,Sign in).tap();constrowscreen.getByRole(listitem).filter({hasText:Design review});awaitrow.getByRole(button,Archive).tap();awaitexpect(screen.getByRole(status)).toHaveText(2 remaining);当你清楚知道要点哪个控件、要校验什么精确文本时用 Locator——零模型调用零不确定性和传统 Playwright 测试写法一致。最有意思的设计回放缓存Replay Cache这是 e2e 相对于直接让 LLM 跑测试的核心差异化能力也是解决AI 测试太贵太慢问题的关键机制。工作原理一个agent.act()步骤在后续有验证步骤确认通过后运行器会把它执行的具体操作点了哪个控件、输入了什么录制成一条 JSON 记录下次运行同一个测试时运行器直接重放这些操作完全不调用模型如果重放中发现控件找不到了、页面结构变了Agent 会从当前屏幕接管继续用模型完成剩余部分运行报告里能看到4 replayed · 1 handed off · 1 missed——哪些步骤是纯重放、哪些是重放失败转人工Agent接管、哪些是完全没缓存命中AI 4.1k tokens · 2 model calls · anthropic/claude-sonnet-4.5 Cache 4 replayed · 1 handed off · 1 missed什么时候才算验证通过缓存不是无条件录制的。只有当agent.act之后紧跟着一个真正验证了结果的步骤——比如expect(locator).toHaveText(...)、agent.assert(...)——缓存才会落盘。像expect(value).toBe(...)这种对纯值的断言、或agent.extract(...)这种只读操作都不算验证不会触发录制。这个设计逼着你写Act 后紧跟检查的测试结构恰好也是端到端测试本该有的严谨性。缓存失效的原因Reason含义no-entry没有匹配的历史记录wrong-context应用当前所在的屏幕和录制时不同不同的 origin/path/querytarget-not-found录制时的控件在 15 秒内没找到end-mismatch所有操作都执行了但录制时期望的最终状态没出现gap某个操作本身无法被重放比如依赖截图读数的操作生产环境还可以开--strict-cache让缓存存在但重放失败直接报错而不是悄悄转人工接管——这避免了每次 CI 都在偷偷花模型调用的钱却没人发现的隐性成本问题。为什么这个设计重要传统的AI 驱动测试工具最大的痛点是成本不可控每次 CI 跑测试都要真实调用一次 LLM几十个测试乘以每天多次 CI 触发账单很快失控。e2e 的回放缓存本质上是把Agent 探索出一条可靠路径和重复执行这条路径分离开——探索阶段付模型调用的钱执行阶段几乎零成本直到应用真的变了才重新付费探索。这比每次都重新问一遍 AI聪明得多。Decision Model 执行器用小模型做选择题e2e-dev/decision提供了另一种执行agent.act/agent.assert的方式不用完整 LLM 做自由发挥的决策而是用一个专门的 Decision Model对每个动作做一次选择题——“该执行哪个操作选哪个元素”——答案是概率分布而不是自由文本只有当动作是输入文本时才交给一个小的文本模型生成具体输入值。import{decisionExecutor}frome2e-dev/decision;constexecutordecisionExecutor({model:typeSafeAi.decisionModel(jev-latest),textModel:openrouter(inception/mercury-2.5),minProbability:0.9,minConfidence:0.8,});这个设计的意义在于模型的输出永远不会直接变成选择器、URL 或密钥——它只能从执行器枚举出的有限选项里选一个索引。minProbability和minConfidence两个阈值可以让信心不足的操作直接判定为不确定而失败而不是赌一个低置信度的猜测。代价是功能有限——不支持视觉、不支持多选列表、不支持拖拽上传适合界面结构规整、测试规模较大的场景用更便宜的方式跑大部分测试。项目地址与资源GitHub: tester-army/e2enpm: e2e文档: e2e.tester.army/docs背后团队: TesterArmyDiscord: tester.army/discord迁移指南: 支持从 Cypress、Detox、Maestro、Playwright、Selenium 迁移总结e2e 代表了一个关于 AI 测试工具的清醒判断让 Agent 操作应用这件事本身不难难的是让它既能适应 UI 变化又不把每次 CI 跑测试都变成一笔模型调用账单。三点值得注意三种步骤的显式分工是对AI 测试过度泛化的纠偏。很多 AI 测试工具试图用一个 Agent 包揽所有事——操作、断言、验证全靠模型判断。e2e 把测试拆成 Goal / Assertion / Locator 三层开发者可以在需要灵活性和需要确定性之间精确选择而不是被迫全盘交给模型或全盘手写选择器。回放缓存把探索成本和执行成本分离这是让 AI 测试在真实 CI 里可持续运行的关键。没有这个机制AI 驱动的端到端测试在生产环境里几乎不可能规模化——模型调用的延迟和费用会随着测试数量线性增长。e2e 用验证通过后录制、后续重放、变化才重新探索的策略让大多数运行几乎零模型成本。Decision Model 执行器展示了不是所有 AI 决策都需要一个完整 LLM。把动作选择变成一个选择题交给专门的 Decision Model比让通用 LLM 自由发挥更便宜、更可控、更可审计——这对需要大规模运行测试套件的团队是一个值得关注的方向。如果你的团队在为 AI 驱动的端到端测试寻找一个能在真实 CI 里稳定跑下去、而不是只能在 demo 里炫技的方案e2e 值得认真评估。探索 PrimeSkills —— 精选 AI agent 和技能工具每一个都经过真实工作流验证。没有炒作只有真正好用的工具。访问我的个人主页获取更多见解和有趣的产品。