一天一个开源项目

开源项目第229期:e2e — 用自然语言写 E2E 测试,还能把 Agent 跑过的操作录成'回放缓存'免模型调用,6k+ Stars

TesterArmy 出品的 Web/移动端端到端测试框架。核心创新:agent.act 用自然语言描述目标让 AI Agent 操作应用,agent.assert 用模型判断断言是否成立,而验证通过后的操作会被录制成回放缓存,后续运行无需模型调用直接重放,直到应用变化才让 Agent 重新接管。TypeScript,Apache-2.0,6k+ Stars。

·约 11 分钟阅读·AI Tools

引言

"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 颗 Star,Apache-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 init

init 会询问引擎类型(Web 或移动端)和模型提供商,然后生成配置文件和一个示例测试。

写一个测试

// tests/checkout.e2e.ts
import { test, expect } from 'e2e';
 
test('a member upgrades to Pro', async ({ app, agent, screen }) => {
  await app.open('/settings/billing');
 
  await agent.act('upgrade the workspace to the Pro plan');
  await agent.assert('the invoice preview shows a prorated amount');
 
  await expect(screen.getByRole('status')).toContainText('Pro');
});

这个测试里三种步骤同时出现:agent.act 让 Agent 自己完成"升级到 Pro"这个目标,agent.assert 让模型判断发票预览的语义是否正确,expect 用精确的 role 选择器验证最终状态。

支持的引擎

包作用
e2eSDK、runner 和 CLI
@e2e-dev/web浏览器引擎:通过 Playwright 驱动 Chromium、Firefox、WebKit
@e2e-dev/mobileiOS/Android 引擎:通过 agent-device 驱动模拟器/真机
@e2e-dev/github把测试结果作为 PR 评论发布的 Reporter
@e2e-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 自己走流程

await agent.act('complete checkout with the test card');
await agent.act('invite {email} as an editor', { params: { email: 'ada@example.test' } });

agent.act 只接受一个目标描述,Agent 自己决定点哪里、输入什么。开发者控制的是目标之间的顺序,不控制目标内部的执行细节。官方给出的实践建议:

  • 每次调用只写一个目标,用屏幕上实际出现的文案描述
  • 测试数据放进 params,密码类数据用 Secret(模型看不到明文)
  • 每次运行会变化的值(如邮箱、时间戳)用 unique() 包裹,这样回放缓存才能正确匹配

Assertion:模型判断语义是否成立

await agent.assert('the dashboard shows a trial badge');
await agent.waitFor('a download link appears', { timeout: 120_000 });
 
const data = await agent.extract('every todo title', {
  schema: z.object({ titles: z.array(z.string()) }),
});

断言模型只看当前屏幕的文本快照和 Agent 的 context,不看之前步骤的历史或摘要——这是故意的隔离设计,避免断言被前面步骤的"叙事"带偏。对于需要视觉判断的场景(图表、布局),可以加 vision: true 让模型看截图。

Locator:精确场景不走模型

await screen.getByRole('button', 'Sign in').tap();
const row = screen.getByRole('listitem').filter({ hasText: 'Design review' });
await row.getByRole('button', 'Archive').tap();
await expect(screen.getByRole('status')).toHaveText('2 remaining');

当你清楚知道要点哪个控件、要校验什么精确文本时,用 Locator——零模型调用,零不确定性,和传统 Playwright 测试写法一致。


最有意思的设计:回放缓存(Replay Cache)

这是 e2e 相对于"直接让 LLM 跑测试"的核心差异化能力,也是解决"AI 测试太贵太慢"问题的关键机制。

工作原理

  1. 一个 agent.act() 步骤在后续有验证步骤确认通过后,运行器会把它执行的具体操作(点了哪个控件、输入了什么)录制成一条 JSON 记录
  2. 下次运行同一个测试时,运行器直接重放这些操作,完全不调用模型
  3. 如果重放中发现控件找不到了、页面结构变了,Agent 会从当前屏幕接管,继续用模型完成剩余部分
  4. 运行报告里能看到: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/query)
target-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 } from '@e2e-dev/decision';
 
const executor = decisionExecutor({
  model: typeSafeAi.decisionModel('jev-latest'),
  textModel: openrouter('inception/mercury-2.5'),
  minProbability: 0.9,
  minConfidence: 0.8,
});

这个设计的意义在于:模型的输出永远不会直接变成选择器、URL 或密钥——它只能从执行器枚举出的有限选项里选一个索引。minProbability 和 minConfidence 两个阈值可以让"信心不足的操作"直接判定为不确定而失败,而不是赌一个低置信度的猜测。代价是功能有限——不支持视觉、不支持多选列表、不支持拖拽上传,适合界面结构规整、测试规模较大的场景用更便宜的方式跑大部分测试。


项目地址与资源


总结

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 和技能工具,每一个都经过真实工作流验证。没有炒作,只有真正好用的工具。

访问我的个人主页,获取更多见解和有趣的产品。