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

引言

"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

快速上手

安装

bash 复制代码
npx e2e init

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

写一个测试

ts 复制代码
// 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 选择器验证最终状态。

支持的引擎

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

ts 复制代码
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:模型判断语义是否成立

ts 复制代码
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:精确场景不走模型

ts 复制代码
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)接管、哪些是完全没缓存命中
text 复制代码
           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 对每个动作做一次选择题------"该执行哪个操作,选哪个元素"------答案是概率分布而不是自由文本;只有当动作是"输入文本"时,才交给一个小的文本模型生成具体输入值。

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

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

相关推荐
东风破_1 小时前
从 Neo4j 到 GraphRAG:用 Text-to-Cypher 构建图检索 RAG
人工智能·后端
冬奇Lab1 小时前
LLM 自动化测试系列(05):移动端自动化(一)——ARTEMIS 的双模式架构拆解
人工智能·测试
DisonTangor1 小时前
llama.cpp 新特性:决策模型
人工智能·开源·aigc
鲲穹AI种草1 小时前
AI 生成 PPT 工具怎么选?鲲穹 PPT 功能实测与横向对比
人工智能·powerpoint
AI技术新视界1 小时前
Strata 的工作原理
人工智能·推理引擎·本地ai
2501_926978332 小时前
给自指系统接一个外部锚 —— 一个关于「用 AI 观察自己」的方法
人工智能·经验分享·笔记·机器学习·ai写作
不悔哥2 小时前
小智AI聊天机器人:ESP32上的开源语音助手拆解
人工智能·机器人·开源
枯木◊靠推文躺平版2 小时前
2026 企业级 AI 办公平台选型指南:如何评估可落地的办公 AI 能力
大数据·人工智能
空奈qwq2 小时前
ANN 全连接神经网络进阶:从反向传播到完整实战
人工智能·深度学习·神经网络