「漫说测试」· 实战实测
一个真实跑通的 demo 全记录:装包 → 配置 → 用例 → 出报告,附完整可运行项目 + 指令执行层级 + 踩坑指南。
【贴图1】
一、先说结论
能跑,而且很好上手。
我用tester-army/e2e(v0.18.0)建了一个最小项目:一个登录表单 + 购物车页面,用浏览器真实点击「登录 → 加购 ×2」,两条用例全绿,耗时3.45 秒,并生成了机器可读的report.json。
最香的一点:确定性用例(只用定位器 + 断言)全程零模型调用、零 API 费用——这是它比一堆「AI 测试」噱头工具更务实的地方。
【贴图2】
二、它到底是什么?
e2e是一个开源的 agentic 端到端测试框架,核心玩法是:
用自然语言描述目标,让 agent 自己驱动页面(
agent.act/agent.assert);也可以用传统定位器 + 断言做精确校验(
screen+expect);关键设计:agent 步骤跑通一次会被记录,下次运行直接重放、不再调模型,直到页面变化——所以模型成本可控;
浏览器引擎底层用 Playwright,移动端走 iOS/Android 模拟器;
官网开源、Apache-2.0 许可 ^1。
一句话:它把「AI 的灵活」和「断言的确定」塞进了同一个测试文件里。
【贴图3】
【贴图4】
【贴图5】
【贴图6】
三、先看清结构:完整项目 + 指令执行层级
这一步 90% 的人会踩——不是框架难,是**「命令该在哪一层跑」没说清**。先看完整结构:
e2e-demo/ ← 「项目根」:所有命令都在这一层执行 ├── package.json ← 依赖与脚本 ├── tsconfig.json ← TS 配置(e2e.config.ts / tests 用) ├── e2e.config.ts ← ⭐ 测试配置(runner 自管被测进程) ├── app/ │ └── server.js ← 被测应用(40 行 Node 静态站) ├── tests/ │ ├── checkout.e2e.ts ← 确定性用例(零模型) │ └── agent-example.e2e.ts ← agent 示例(默认 skip) └── .e2e/ ← 运行期自动生成(勿手动建) ├── logs/app.log └── report.json指令在哪个层级执行(最容易搞错的地方):
|
指令
|
在哪个目录执行
|
说明
|
| — | — | — |
|npm install e2e@latest|项目根e2e-demo/|
装核心 CLI/SDK
|
|npm install -D @e2e-dev/web|项目根|
浏览器引擎(别再装 playwright)
|
|sudo ./node_modules/.bin/e2e-web install chromium --with-deps|项目根|
补 Chromium 系统库(容器必备)
|
|node app/server.js|项目根|
手动起被测应用(一般不用,runner 会自管)
|
|npx e2e run|项目根|
⭐ 跑测试;必须在含e2e.config.ts的目录执行
|
|npx e2e login openai|项目根|
订阅登录模型(用 agent 步骤时)
|
|export AI_GATEWAY_API_KEY=***|
项目根
|
API Key(用 agent 步骤时)
|
一句话:除了「进目录」那两条(
mkdir e2e-demo && cd e2e-demo),其余命令一律在「项目根 e2e-demo/」里执行。配置里的相对路径(tests/**/*.e2e.ts、app/server.js、.e2e/logs/app.log)也都以项目根为基准。npx e2e run如果在子目录里跑,找不到e2e.config.ts,就会报错。
【配图·fig-tarmy-d:项目结构与指令层级】
四、环境准备
|
项目
|
要求
|
| — | — |
|
Node.js
|
≥ 24.8(或 22.22.3+)
|
|
包管理
|
npm / pnpm 均可
|
|
浏览器依赖
|
首次需补 Chromium 系统库(见踩坑部分)
|
我本机环境:Node v24.18.0+npm 11.16.0。
五、三步跑通
第 0 步:建目录、初始化(先「进项目根」)
mkdire2e-demo&&cde2e-demonpminit-y第 1 步:装包(在项目根)
# 核心 CLI / SDKnpminstalle2e@latest# 浏览器引擎(它内部锁死 playwright-core,千万别再单独装 playwright)npminstall--save-dev @e2e-dev/web⚠️ 官方明确要求:浏览器测试用
@e2e-dev/web,它会精确锁定playwright-core版本;不要额外安装playwright,否则版本打架。
【贴图7】
【贴图8】
第 2 步:造一个被测应用(在项目根,写app/server.js)
为了不依赖外部网站,我写了一个 40 行的 Node 静态站app/server.js:带一个登录表单和一个「加入购物车」按钮。
// app/server.js const http=require('node:http');const PORT=Number(process.env.PORT||4173);const PAGE=`<!doctype html><htmllang="en"><head><metacharset="utf-8"><title>Acme Storefront</title></head><body><h1>Acme Storefront</h1><formid="signin"><labelfor="email">Email</label><inputid="email"type="email"><labelfor="password">Password</label><inputid="password"type="password"><buttontype="submit">Sign in</button></form><divid="status"role="status"></div><sectionclass="row"hiddenid="shop"><span>Itemsincart:</span><spanid="cart-count">="cart-count">0</span><buttontype="button"id="add">Add to cart</button></section><script>const status=document.getElementById('status');const shop=document.getElementById('shop');const countEl=document.getElementById('cart-count');letcount=0;document.getElementById('signin').addEventListener('submit',(e)=>{e.preventDefault();const email=document.getElementById('email').value.trim();if(!email){status.textContent='Email required';return;}status.textContent='Signed in as '+ email;shop.hidden=false;});document.getElementById('add').addEventListener('click',()=>{count+=1;countEl.textContent=String(count);});</script></body></html>`;http.createServer((req,res)=>{ if(req.url==='/'){ res.writeHead(200,{'content-type':'text/html;charset=utf-8'});res.end(PAGE);return;} if(req.url==='/healthz'){ res.end('ok');return;} res.writeHead(404);res.end('not found');}).listen(PORT,'127.0.0.1',()=>console.log('app on',PORT));第 3 步:写配置e2e.config.ts(放项目根)
亮点:app.command让 runner自己拉起/结束被测进程,你再也不用手动开 dev server。
// e2e.config.tsimporttype{E2EConfig}from'e2e';import{web}from'@e2e-dev/web';exportdefault{tests:'tests/**/*.e2e.ts', targets:[{name:'web', engine: web(), app:{url:'http://127.0.0.1:4173', command:{executable:'node', args:['app/server.js'], env:{PORT:'4173'}, log:'.e2e/logs/app.log',},},},], // 确定性用例不需要下面这段;要用 agent 步骤再放开并登录模型}satisfies E2EConfig;第 4 步:写用例tests/checkout.e2e.ts(零模型版)
// tests/checkout.e2e.tsimport{test}from'@e2e-dev/web';import{expect}from'e2e';test('a shopper signs in and adds two items to the cart', async({app,screen})=>{await app.open('/');await screen.getByLabel('Email').fill('qa@example.test');await screen.getByLabel('Password').fill('hunter2-hunter2');await screen.getByRole('button',{name:'Sign in'}).click();await expect(screen.getByRole('status')).toContainText('Signed in as qa@example.test');await screen.getByRole('button',{name:'Add to cart'}).click();await screen.getByRole('button',{name:'Add to cart'}).click();await expect(screen.getByTestId('cart-count')).toHaveText('2');});第 5 步:跑!(在项目根)
npx e2e run六、运行结果(真实输出)
RUN e2e v0.18.0 /…/e2e-demo ✓ target"web"commandready 121ms ✓|web|tests/checkout.e2e.ts(2tests)2.78s Test Files1passed(1)Tests2passed(2)Duration3.45s → Report .e2e/report.jsonreport.json里关键字段:"status": "passed"、"exitCode": 0——CI 门禁可以直接拿退出码判断。
【贴图9】
七、踩坑记录(唯一一个)
现象:第一次运行直接报错——
errorwhileloading shared libraries: libatk-1.0.so.0: cannotopenshared objectfile原因:容器/裸机缺少 Chromium 的系统依赖库。
解决(在项目根执行,官方推荐命令,--with-deps会顺带把系统库装好):
sudo./node_modules/.bin/e2e-webinstallchromium --with-deps装完ldconfig -p | grep libatk能看到库,再跑就绿了。非容器环境通常不会遇到这一步(Windows 基本遇不到)。
排错速查表(实测最常撞的两个)
报错①:npm error could not determine executable to run
症状:执行
npx exe run报“找不到可执行文件”。原因:命令拼错了——是
e2e,不是exe。修复:
npx e2e run。
报错②:CONFIG_LOAD_FAILED ... Cannot find package '@e2e-dev/web' ... run npm install
症状:配置加载失败,提示
@e2e-dev/web已在 package.json 声明但没装。原因:直接
npx e2e run时,npx 只临时抓了e2e,没有安装项目依赖。修复:在项目根先
npm install,再npx e2e run。
Windows(PowerShell)注意:
|
事项
|
Linux/macOS
|
Windows(PowerShell)
|
| — | — | — |
|
装 Chromium
|sudo ./node_modules/.bin/e2e-web install chromium --with-deps|npx e2e-web install chromium
(去掉 sudo)
|
|
跑测试
|npx e2e run|npx e2e run
,或更稳的.\node_modules\.bin\e2e run
|
|
核对
|ls node_modules/@e2e-dev|dir node_modules\@e2e-dev
(应有web)
|
顺带:关遥测用
npx e2e telemetry disable(或设E2E_TELEMETRY_DISABLED=1)。
八、进阶:加上 agent(自然语言)步骤
确定性用例很稳,但真正「agentic」的部分长这样:
// 需要先在 config 里配置模型 + 登录 await agent.act('sign in with the email qa@example.test and the password hunter2-hunter2');await agent.assert('the page confirms the user is signed in');启用方式二选一(在项目根):
# 方式 A:用订阅登录(ChatGPT Plus/Pro)npx e2e login openai# 方式 B:用 API KeyexportAI_GATEWAY_API_KEY=***# 或 OPENROUTER_API_KEY=***💡 我把 agent 示例单独放一个文件并
test.skip,这样没有模型的环境也能跑确定性套件,有模型时再单独开——团队协作很实用。
九、我的使用建议
✅适合:
想在现有 Playwright/Selenium 体系上,低成本试水 AI 测试的团队;
需要「自然语言探索 + 精确断言」混合的复杂业务流程;
对模型成本敏感(重放机制帮你省钱)。
⚠️注意:
当前0.18.x,尚未到 1.0,小版本间 API 可能变,适合先在非关键流程试点;
agent 步骤质量依赖模型与页面语义,配置里给足
context/system提示会更稳。
【贴图10】
🎁 加料包:完整可运行项目,直接拿走
上面这套demo 我打包好了——e2e-demo/是能直接跑的真项目(package.json、e2e.config.ts、app/server.js、tests ×2 全都在),配上一份《tester-army/e2e 快速上手手册》
附:一键复现清单
e2e-demo/ ├── app/server.js# 被测应用├── e2e.config.ts# 测试配置(自管被测进程)├── tests/checkout.e2e.ts# 确定性用例(零模型)├── tests/agent-example.e2e.ts# agent 示例(默认 skip)└── .e2e/report.json# 运行报告(自动生成)cde2e-demo# ← 进项目根npminstalle2e@latest&&npminstall-D@e2e-dev/websudo./node_modules/.bin/e2e-webinstallchromium --with-deps npx e2e run# ← 在项目根跑本文为真实环境实测记录,代码均已在本地跑通。