团队里谈「用 AI 做端到端」时,常见两种落地,最后都不太好维护。
一种是让模型生成 Playwright 脚本,生成完就冻结成定位器。当时省事,按钮文案或层级一改,红的还是选择器,修的还是人。模型只出现在写脚本的那一下。
另一种是整条用例都写成自然语言,每次运行都让模型看页面、推理、点击。路径灵活,但没改过的页面也会重复烧 token,而且模型当场决策,CI 里今天绿、明天红并不稀奇。
TesterArmy 的 e2e 走的是第三条:同一条测试里,不确定的路径交给 agent,必须稳定的结果交给定位器和断言。仓库 README 把这件事概括成:用自然语言描述目标,由 agent 驱动应用达成;结果仍用 locator 和断言检查。协议是 Apache-2.0,覆盖 Web 和移动端。
下面不谈热度,只谈已经有自动化套件的团队该怎么拆。

从左到右是确定性断言、动作回放、agent 看页面,只是概念示意,不是产品截图或实测数据。
一条测试里谁负责什么
可以按失败成本来分,而不是按「是不是 AI 项目」来分。
- 结果必须可重复核对:留给
expect。金额、状态文案、是否进入某个路由,这些不应该交给模型「看起来对了」。 - 路径长、选择器脆、改版频繁:交给
agent.act()。你描述目标,不描述第几个 div。 - 这条用例根本没有 agent 步骤:就不该产生模型调用。README 写明,没有 agent 步骤的测试不需要模型。这意味着可以一条一条往现有套件里加,而不是新起一套纯 AI 回归。
自拟一个邀请加入团队的场景,只用文档里已经公开的写法(app.open、agent.act、agent.assert、screen.getByRole):
ts
import { test, expect } from 'e2e';
test('invitee joins the default team', async ({ app, agent, screen }) => {
await app.open('/invite/accept');
await agent.act('accept the invite and stay on the default team');
await agent.assert('the header shows the invited team name');
await expect(screen.getByRole('status')).toContainText('joined');
});
agent 负责把邀请流程走完;最后一行仍然是普通断言。审用例时看的是「目标是否说清楚、断言是否钉死结果」,不是逐行看选择器。
回放改变的是账单,不是正确性
混合本身解决不了费用。贵的是「每次 CI 都重新推理」。
e2e 的做法是:被后续断言验证过的 agent 步骤会记下动作;下次应用没变,就回放这些动作,不再调模型。应用变了、回放对不上,才重新规划,并记下新动作。README 的原话是:next run replays them with no model calls until the app changes。
对排期有用的推论是:模型费用应该跟着「这周真正改过的界面」走,而不是跟着回归条数走。十个模块里只有结算页改了,就只该为结算相关的 agent 步骤付钱,其余回放。反过来,如果你们的页面每周都大改,回放几乎总是失效,那这层节省就不成立,不该为了「AI 测试」硬迁。
正确性仍然靠断言,不靠回放。回放只是在界面没变时跳过推理;断言失败就说明结果不对,该修的是产品或用例,不是缓存本身。
和现有技术栈怎么接
Web 引擎是 @e2e-dev/web,浏览器走 Playwright,Chromium、Firefox、WebKit 都在包说明里。移动端是 @e2e-dev/mobile,打到 iOS 模拟器和 Android 模拟器。测试写法仍是同一套 test / expect / agent 步骤,差别主要在引擎和夹具,而不是再学一套断言库。
官方 examples/ 里已经有可以单独跑通的工程:Vite、Next.js、Astro、Angular、Expo、SwiftUI、Jetpack Compose、Kotlin Multiplatform、Flutter、.NET MAUI。选型时先对一下自己的壳,比先看 star 有用。
从 Playwright、Cypress 这类框架迁过来,值得迁的通常不是全部定位器,而是那些已经反复修、又很难写稳的步骤。稳定的 getByRole 不必换成自然语言。
安装入口就是:
bash
npx e2e init
npx e2e run
init 会问引擎(Web 或 Mobile)和模型来源,然后写下配置和一条示例测试。建议先把「不调模型的示例」跑绿,再加 agent 步骤。Node 版本、Windows 是否要 WSL、模拟器要不要本地 Xcode / Android SDK,以 quickstart 当前说明为准,不要凭旧文里的版本号。
模型、密钥和给编码代理看的文档
模型不是框架内置的。README 写的是自带订阅、API key,或本地模型。配置集中在 init 生成的 e2e.config.ts。密钥放环境变量,不要写进用例或系统提示词;报告里也不该出现明文。
另一件和「人写脚本」不同的设计是:整套文档打进 e2e 这个 npm 包,路径在 node_modules/e2e/docs。编码代理可以离线读,不必临时去爬官网。首页还给代理准备了 npx skills add tester-army/e2e。实际分工可以是:人规定哪些结果必须断言,代理起草 agent 步骤,人看失败报告里的步骤、截图和 trace。
包也不只本地这几个。除了主包 e2e、Web、Mobile,还有把结果贴到 GitHub PR 的 @e2e-dev/github,以及 Kernel、Lightpanda、smol、EAS、Limrun、TestMu 这类托管浏览器或模拟器。本地还没稳定时,不必先接云端包。
CLI 会上报匿名使用数据(跑了哪条命令、哪个引擎、失败落在哪),不包含用例内容、应用内容和凭证。不想要就 npx e2e telemetry disable,或设置 E2E_TELEMETRY_DISABLED=1。
现在不该整库替换的原因
仓库自己标了:走向 1.0 的过程中,minor 之间 API 和配置仍可能变。核心回归如果今天就全押上去,要接受跟着改配置。
第一次执行 agent 步骤才会真正调模型,界面越复杂越贵。回放能压住之后的 CI,压不住「第一次全量铺开」那次账单。可以先挑三五条最脆的路径做试点,看回放命中率和失败是否可诊断,再决定铺开范围。
还有一层边界:开源框架是 Apache-2.0;TesterArmy 另外有一个在 PR 或定时任务上跑自然语言测试的托管平台。用框架不等于买平台,后续是否收费以他们的产品说明为准,不要把这两件事写成同一个交付物。
可以带走的判断
工具可以先不装,拆分方式可以先用在现有套件上。
- 断言守住必须稳定的结果,agent 只吃写不稳的路径。
- 模型调用应当发生在界面变化之后,而不是每一次 CI。
- 没有 agent 步骤的老用例继续当普通测试跑,迁移按条进行。
本文按仓库 README 和文档里的公开能力重新整理,示例是为了说明 API,不是复述某篇评测的数据或结构。star、下载量和第三方背书会变,选型时以你自己的套件能不能回放、断言能不能钉死结果为准。