news 2026/10/23 6:11:14

e2e Bug Bash 实战指南:并行 explore 章程、缺陷分流与复现测试验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
e2e Bug Bash 实战指南:并行 explore 章程、缺陷分流与复现测试验证
  • 测试
  • 测试智能体
  • 人工智能
  • 浏览器控制
  • CLI

【免费下载链接】e2e

Next generation e2e testing framework for web and mobile apps.

项目地址:https://gitcode.com/GitHub_Trending/e2e6/e2e
点击查看免费下载

导读

本指南以仓库内技能文档 bug-bash.md 为核心,讲解如何在 e2e 框架中组织一次完整的 Bug Bash:把一次探索拆成多个并行的e2e explore章程(charter),每个章程针对一个区域、一种姿态,最终通过“缺陷分流 + 复现测试”把每个候选缺陷证明为"确认的 bug"或"驳回的误报"。读完本文,你将掌握从准备工作、章程规划、并行派出、结果合并、分流、验证到报告的七阶段完整流程,并理解report_finding工具、run.explore报告结构与探索预算在 explore 源码 中的实现原理。

什么是 Bug Bash

Bug Bash 的定义很简洁:同时发起多个e2e explore运行,每个运行一个章程,然后在验证阶段把每一个声称的缺陷改写成一个"会因该缺陷而失败"的复现测试。完整流程是:

  1. 规划章程(Plan the charters)
  2. 并行派出(Fan them out)
  3. 合并发现(Merge the findings)
  4. 证明每个 bug(Prove each bug)

最终只报告确认的缺陷,且每个缺陷都附带一个失败的复现测试。它既不是跑一遍测试套件,也不是让一个 Agent 全应用乱逛:一次 Bug Bash 是"许多次目标明确的探索 + 一轮严格的证伪"。

第 1 步:准备(Prepare)

准备阶段决定整场 Bug Bash 的成败。文档列出以下关键点。

1.1 配置与认证

  • 需要一个包含 target 和持有模型的 agent 的配置(主题见 setup.md),并为模型提供方配置好认证。
  • 配置中必须满足e2e explore的最低要求:有 target、有带模型的 agent,仅此即可。

1.2 让应用同时服务多个探索者

一次 Bug Bash 有多个探索者并发访问应用,必须保证应用能同时服务多个会话:

  • 启动一次、复用进程:在 target 的app.command上设置reuseExisting: true;或
  • 端口 0 自由分配:把 URL 声明为端口0,让每次运行自己启动应用并占用一个空闲端口。

关键陷阱:reuseExisting在设置了CI时会被忽略(很多 Agent 沙箱都设了CI),此时要么用端口0,要么取消设置CI。一个固定端口如果既不复用、又被多个探索者抢占,那么除第一个外的所有运行都会失败。

  • 自带技术栈的命令要格外小心:如果app.command会拉起一整套栈(例如一个随进程退出而创建/删除的数据库),那么第一个结束的探索者就会把数据库从其余探索者脚下抽走。正确做法是:你自己用配置里的命令和环境把栈启动一次,然后用一个"不声明 command"的 Bug Bash 配置去探索(下面会给出该配置)。

  • 优先探索生产构建:如果项目有生产构建,用它。开发服务器"首次访问某路由时才编译"的行为,会被探索者误读成死链。

  • 每个章程一个一次性工作区/用户:用项目自己的 fixtures 或 seed 脚本播种数据,并把每个账号声明为一个凭据(命名为bb-<slug>)。共享账号的探索者会把彼此的编辑报告成 bug。

1.3 登录态与上下文约束

  • 从已保存的会话开始登录章程:e2e explore --session <name>会先运行保存该会话的 setup 测试,然后以登录状态探索(详见 explore.md)。注意:如果 setup 通过输入密码登录,此后探索的截图会被打码扣留;用 cookie 或 API 调用登录则保留截图(详见 writing-tests.md)。每个拥有独立账号的章程都需要自己的 setup 和 session。
  • 把本地应用做不到的事写进 agent 的context:没有 key 的集成、哪些是 seed 数据、绝不能点的东西(付费运行、真实账号)。还要加入第 5 步分流出的"探索者盲区"清单(下面的配置里直接内置了一句示例);不加这些盲区,这类家族(新标签页、无限滚动、懒加载图片等)会霸占整份发现清单。

1.4 对已部署站点的只读约束

如果 Bug Bash 针对的是别人在用的线上站点,则必须是只读的:不注册、不登录、不提交,URL 里不做注入形状的操作,不发请求循环。注意:WAF 拦截是防火墙在正常工作,不是发现,而且它可能跟随运行者的 IP 进入后面每一个章程。

1.5 预算与引擎参数

  • 每个探索步骤需要 40 或更多的maxSteps和maxModelCalls;按测试步骤调优的配置(maxSteps: 15)会让探索者饿死。注意这是"每一步"的预算,与--max-steps(计算一个章程的步数)是两回事。
  • 移动端 target:每个设备声明一个 target,给每个探索者和验证者各自的 target(主题见 setup.md)。
  • 跳过--headed。在能录制的引擎上,--video会为每个确认的 bug 留下一份可回放的录像。

1.6 Bug Bash 专属配置

文档给出一个典型的e2e.bugbash.config.ts。它通常不被纳入版本控制,因为里面展开了项目配置并覆盖了 Bug Bash 所需的设置。把导入类型写成E2EConfig,可以让shared.tests和shared.credentials在基础配置两者都不声明时依然能编译:

// e2e.bugbash.config.ts import type { E2EConfig } from 'e2e'; import { web } from '@e2e-dev/web'; import { gateway } from 'ai'; import base from './e2e.config.ts'; const shared: E2EConfig = base; // What the local app cannot do, plus the explorer's blind spots (step 5's artifact bucket). const context = 'Sign in with the credential the goal names. The local app sends no email and has no AI key. Never start a paid run or connect an integration. ' + 'Not bugs: a link that opens a new tab leaves this one unchanged; accessible text splits around inline links, so judge copy by the rendered screen when a screenshot is available and never report split text alone as broken copy; an infinite-scroll "Loading more" sentinel loads when scrolled into view; images lazy-load, so scroll and wait before calling one blank.'; const persona = { model: gateway('openai/gpt-6-luna-fast'), maxSteps: 40, maxModelCalls: 40, context }; export default { ...shared, // The project's tests, so a repro can use its setup tests' sessions, plus the repro tests from step 6. tests: [shared.tests ?? 'tests/**/*.e2e.ts', 'tests/bugbash/**/*.e2e.ts'].flat(), // The app already runs: no command. targets: [{ name: 'web', engine: web(), app: { url: 'http://127.0.0.1:3000' } }], retries: 0, reporters: ['list'], credentials: { ...shared.credentials, // The seed script's password, from the environment rather than the file. 'bb-cart': { username: 'bb-cart@example.test', password: process.env.BUGBASH_PASSWORD ?? '' }, 'bb-account': { username: 'bb-account@example.test', password: process.env.BUGBASH_PASSWORD ?? '' }, }, // The postures from step 2 as personas: same model and budgets, a different stance; each charter picks one with --agent (step 3). agents: { default: persona, skeptic: { ...persona, system: 'Distrust every number, date, count, and claim on screen; cross-check each against every other place it appears.' }, fuzzer: { ...persona, system: "At every input, run the goal's input matrix before anything else, judging each entry before the next. Never take the happy path." }, }, } satisfies E2EConfig;

配置要点:

  • tests合并了项目原有测试与tests/bugbash/**/*.e2e.ts,这样复现测试可以复用项目 setup 测试保存的会话;
  • target 只声明url、不声明command,因为应用已在第 1.2 节由你手动启动;
  • retries: 0:探索是单次尝试,重试模式无意义;
  • 凭据密码来自环境变量而非文件(process.env.BUGBASH_PASSWORD ?? ''),符合凭据不入库的规范(setup.md);
  • 第 2 步规划的"姿态"以 persona 形式落地:skeptic(怀疑一切数字与文案)、fuzzer(每个输入都先跑输入矩阵),由每个章程用--agent挑选。

启动前必须先把BUGBASH_PASSWORD设为 6 个或更多字符,否则配置加载失败(静态密码长度校验,见 setup.md 中credentials的 6+ code points 规则)。之后对下面所有命令都传--config e2e.bugbash.config.ts,并通过 MCP 传open_session {config: "e2e.bugbash.config.ts"}(详见 mcp.md)。

第 2 步:规划章程(Plan charters)

一个章程就是一条e2e explore目标:一个区域、一种姿态、一句话,写明起始路由,必要时写明凭据(例如Sign in as credential bb-cart. Starting at /cart, ...)。动手前先读路由、导航和表单;如果是分支,用git diff --stat对比基线。

文档给出五种姿态的章程模板:

姿态章程形态
First-time userStarting at /signup, sign up and complete onboarding like a first-time user; report anything confusing, broken, or inconsistent
Numbers and copyStarting at /cart, change quantities and apply a coupon; check every price, total, and label against the rest of the page
Edge inputStarting at /settings/profile, submit each field empty, too long, with unicode and with leading spaces; report validation that is missing or wrong
StateStarting at /projects, create, rename, and delete a project, reloading and going back after each; report state that is lost or stale
Error pathsStarting at /login, try a wrong password, an unknown account, and a locked account; report errors that are missing, misleading, or leak detail

目标数量:五到十个章程,每个有自己的 slug。重叠是允许的——重复项会在第 4 步合并。

每个姿态要匹配一个 persona(上面配置中的 agent 定义),在第 3 步按章程挑选:普通 agent 会径直走过"某页一个统计数字与另一页自相矛盾"的现场,而 skeptic 能抓住它。边缘输入类章程必须点名它的精确矩阵(空值、300 字符字符串、unicode、前导空格、字面特殊字符),否则它会把整个时间预算花在矩阵上而没判断出任何一条结果。

第 3 步:并行派出(Fan out)

每个章程一条e2e explore命令,配独立输出目录:

  • --output .e2e/bugbash/<slug>会写入report.json和results/;
  • --reporter list,markdown额外生成summary.md。

注意 git 痕迹:e2e init只忽略特定的.e2e/路径,不会忽略.e2e/bugbash/。要么把它加进.gitignore,要么结束后删除;开始下一场 Bug Bash 前务必先删掉旧的。charters.txt及其下的日志归你所有;其余是 runner 的输出,只读。

用shell 后台任务并行跑,四个一批,不要用 subagent。每行一个章程,格式为slug|target|agent|charter,agent 一栏填写 persona 名,然后用(xargs -0 -P是 GNU 和 BSD 扩展,macOS 和 Linux 都有):

mkdir -p .e2e/bugbash cat > .e2e/bugbash/charters.txt <<'CHARTERS' cart|web|skeptic|Starting at /cart, change quantities and apply a coupon; check every price, total, and label against the rest of the page account|web|fuzzer|Starting at /settings/profile, submit each field empty, a 300-character value, unicode, and leading spaces; report validation that is missing or wrong CHARTERS while IFS='|' read -r slug target agent charter; do [ -n "$slug" ] && printf '%s\0%s\0%s\0%s\0' "$slug" "$target" "$agent" "$charter" done < .e2e/bugbash/charters.txt | xargs -0 -n 4 -P 4 sh -c \ 'npx e2e explore "$4" --config e2e.bugbash.config.ts --target "$2" --agent "$3" --output ".e2e/bugbash/$1" --max-steps 6 --video --reporter list,markdown < /dev/null > ".e2e/bugbash/$1.log" 2>&1' _

日志的摘要会打印AI(成本)和Duration。退出码1表示报告了 issues——无论哪种情况都要读日志;退出码2和3是 setup 和环境问题,修复后单独重跑那个章程即可。

从源码看,这些预算参数有明确的上下界:STEP_BOUNDS为 1 到 12、默认 8,TIMEOUT_BOUNDS为 180000 到 900000 毫秒、默认 600000(见 explore/index.ts)。一次探索在超预算、步数上限、时钟耗尽或连续三个失败/阻塞步骤后结束(详见 explore.md 的"一次运行做了什么")。

第 4 步:合并(Merge)

读取每个日志的Findings部分(主题见 explore.md);summary.md内容相同,report.json中的完整记录在run.explore下。录像位于.e2e/bugbash/<slug>/results/下该 attempt 的video/目录。

合并描述同一缺陷的发现:同路径、同损坏行为。保留最清晰的重现步骤和所有命中它的章程。警告单独列表存放,除非用户明确要求打磨项。

一个值得警惕的场景:某个章程填过密码、或其会话的 setup 填过密码,则从那时起不再打印evidence行。但其录像不会被打码:分享前要检查录像里有没有机密(主题见 writing-tests.md 的 Sign-in sessions——一旦填充了 secret,模型像素与断言截图会从此扣留,只有browser.setCookies这类不填密码的登录方式能保留截图)。

合并环节的源码视角:run.explore记录

探索的状态机实现在 explore/state.ts:ExploreState持有 goal、budgets、steps、findings,其快照就是报告中的run.explore。每条自由文本都被裁剪到 schema 规定的上限(state.ts 顶部常量):

  • 标题MAX_TITLE_CHARS = 200
  • 指令MAX_INSTRUCTION_CHARS = 2_000
  • 摘要MAX_SUMMARY_CHARS = 4_000
  • expected/actual 细节MAX_DETAIL_CHARS = 2_000
  • 复现步骤最多MAX_REPRODUCTION_STEPS = 20条、每条MAX_REPRODUCTION_CHARS = 500
  • 路径MAX_PATH_CHARS = 2_048

run.explore记录结构如下(见 explore.md):

{ "goal": "...", "budgets": { "maxSteps": 8, "timeoutMs": 600000 }, "ended": "finished | step-limit | time | stuck | aborted", "summary": "the closing assessment", "steps": [{ "index": 1, "title": "...", "instruction": "...", "status": "passed | failed | blocked | exhausted", "summary": "...", "errorCode": "...", "startedAt": "...", "durationMs": 0 }], "findings": [{ "id": "<uuid>", "index": 0, "step": 1, "kind": "issue", "severity": 4, "title": "...", "expected": "...", "actual": "...", "reproduction": ["..."], "path": "/cart", "observationRevision": "...", "artifactId": "<attempt id>:artifact:2", "reportedAt": "..." }] }
  • 步骤仅在未通过时带errorCode;finding 仅在已知时带step、path、observationRevision、artifactId。
  • artifactId指向 attempt 的artifacts中file为explore的证据截图。
  • 列表报告器会实时打印每条 finding,格式为⚑ high issue Title (/path),并依据严重度着色(见 list-explore.ts);严重度词汇为 critical 5、high 4、medium 3、low 2、trivial 1。终局Findings区按"issues 优先、严重度高者优先"排列,每条带路径、截图路径、expected vs actual 与复现步骤。

第 5 步:分流(Triage)

在写任何测试之前,先给每条发现分类。读源码来分类,这是文档反复强调的纪律。分流桶如下:

桶标志结果
Explorer artifact"死了的"target="_blank"链接(其目标在弹窗捕获或直接导航时其实能打开)、截图中完整呈现却被判为坏句的文案、没人滚动到的 "Loading more" 哨兵、懒加载的图片或嵌入用那条裁决它的检查驳回;最先处理这个桶。目标从未打开的新标签页链接仍保留为候选
Environment失败只因本地栈缺少某个 key、服务或限额(邮件服务商、AI key、计费套餐)驳回并点名变量或服务;若应用以生产用户会看到的方式处理失败不当(如暴露原始错误),则另行记录
Design代码、测试或文案表明该行为是有意为之驳回并引用出处
Fixtureseed 数据缺少真实记录总有的字段驳回并点名字段
Candidate以上都不是进入第 6 步验证

注意分流必须"先于写测试"进行,否则会把大量时间浪费在证明注定要驳回的 artifact 类误报上。

第 6 步:验证(Verify)

一条 finding 只是模型的声称;报告它之前必须证明每个候选。如果你的客户端能启动 subagent(例如 Claude Code 的 Agent 或 Task 工具),按区域各起一个,带上日志打印的三到五条候选和这些步骤,四个一批(e2e mcp服务器默认 4 个会话上限,见 mcp.md)。每个 subagent 按 finding 回报:confirmed 或 rejected、能读源码时的根因(file:line格式)、复现测试路径、以及它看到的失败。没有 subagent 就一个区域一个区域地验证。

验证分四步:

  1. 把actual对照截图读一遍(无截图看录像)。证据与发现矛盾就在这里驳回。先处理 artifact 桶:"死链"的目标必须真的打不开才算数(有合法 href 但preventDefault阻止的仍是死链);文案声称必须出现在渲染截图里。
  2. 写复现测试:跟随复现步骤、断言预期行为,使它在今天失败、bug 修复后通过。放在配置testsglob 覆盖的目录下的bugbash/里(默认即tests/bugbash/<slug>.e2e.ts)——glob 匹配不到的文件永远不会被选中,无论你往e2e run传什么路径。基于项目 fixtures 构建(test.extendfixture、setup 测试的会话,见 writing-tests.md)。优先用screen动作和带精确值的expect;对会变化的步骤用agent.act,对只有判断力能确认的结果用agent.assert。测试加{ tags: ['bugbash'] }。
  3. 从活应用拿精确 locator:注册e2e mcp服务器后,用 Bug Bash 配置open_session,把会话 id 传给每次调用,走一遍复现,写 locator 前先用locate验证(主题见 mcp.md)。用完关闭会话。
  4. 单独运行该文件:npx e2e run tests/bugbash/<slug>.e2e.ts。只有它因编码了该 bug 的断言报出ASSERTION_FAILED才算确认。任何其他失败(LOCATOR_NOT_FOUND、超时、setup 错误)都说明测试写错了:修好重跑。测试通过则说明 bug 没有复现:驳回该发现、说明理由,并把测试移出tests/bugbash/(移到.e2e/bugbash/extra-tests/,或提议作为回归测试)。只有失败的复现测试可以留在这里。

从实现看,"报告 finding"是探索者独有的一枚工具:report_finding(常量FINDING_TOOL_NAME,见 explore/executor.ts),它只在e2e explore下挂载(见 action-names.ts)。而规划下一步的 planner 是以agent.extract步骤运行的:一次结构化模型调用读取 goal、此前的步骤与当前屏幕,用 schema 校验输出step | finish二选一的决策(title + 具体章程指令 / 收尾评估),见 explore/plan.ts。复现测试要断言的"预期行为"恰好可以取自 finding 的reproduction步骤与expected字段——文档明确说"把 finding 变成测试:reproduction步骤就是agent.act()指令或screen.*动作,expected就是断言"。

第 7 步:报告(Report)

报告以已确认的 bug 开头,最严重的排最前。每个 bug 包含:

  • 标题
  • 路径
  • 一行 expected vs actual
  • 已知时的根因
  • 步骤
  • 截图与录像路径
  • 复现测试
  • 发现它的章程

之后按顺序是:构成生产风险、标记为未验证的环境类候选→按原因分组(environment、design、fixture、did not reproduce)的驳回发现→警告。最后列出:跑过的章程、它们的成本、以及没有章程覆盖到的区域。

复现测试在 bug 修复前一直是失败的:如果项目的testsglob 覆盖了tests/bugbash/,其门禁运行要用npx e2e run --exclude-tag bugbash把它们排除,或者让它们保持未提交。提议修复每个 bug:复现测试变绿就是证明,修复后它作为回归测试留在项目里,并去掉bugbash标签。

规则

  • 绝不把未验证的发现报告为 bug。"探索者报告的"不是"确认的"。
  • 一个章程一个区域。横跨整个应用的章程会在步数预算耗尽时什么都只蹭了一遍。
  • 应用为开发而自带的 seed 数据和测试账号不是 bug;在 agent 的context里说明这一点。
  • 把项目的文件保持原样:Bug Bash 配置、seed 脚本和复现测试在用户另有要求前保持未跟踪;用户结束后,停掉你启动的栈。

小结:Bug Bash 的关键心法

  • 预算饥饿是最大的隐性失败:探索者每一步需要 40 以上的maxSteps/maxModelCalls,与测试步骤的预算完全不同。
  • 上下文塑造探索者:把"本地做不到的事"和"探索者盲区"写进context,否则 artifact 家族会淹没发现。
  • 验证先于报告:只有ASSERTION_FAILED于编码该 bug 的断言,才叫确认;通过就是驳回。
  • 复现测试是 bug 的载体:它留在tests/bugbash/直到 bug 修复,修复后升级为回归测试。

这套流程把"模型声称的缺陷"严格降级为"可证伪的工程事实",而 e2e 提供的e2e explore、run.explore记录、report_finding工具与 MCP 会话正好构成了这条证据链的每一环。相关主题文档可继续阅读:SKILL.md、explore.md、mcp.md、writing-tests.md 与 setup.md。

  • 测试
  • 测试智能体
  • 人工智能
  • 浏览器控制
  • CLI

【免费下载链接】e2e

Next generation e2e testing framework for web and mobile apps.

项目地址:https://gitcode.com/GitHub_Trending/e2e6/e2e
点击查看免费下载

相关推荐

上一篇:Firebase Admin Python SDK 教程
下一篇:BabyAI安全考虑:确保AI智能体可靠执行指令的最佳实践

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 23:25:58

Qt与IAR协同:嵌入式开发双工具链实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/18 7:00:45

Linux:搜索命令which、whereis、loacte和find详解

相关文章 Linux专栏https://blog.csdn.net/weixin_45791458/category_12234591.html 目录 1、which 2、whereis 3、locate 4、find 1、which which命令通常被用来搜索拥有可执行状态的文件&#xff08;命令&#xff09;&#xff0c;因为它在环境变量$PATH指定的目录中搜索命令…

作者头像 李华
网站建设 2026/10/18 2:58:38

YC-6869蓝牙立体声DC-5V音乐模块

YC-6869蓝牙模块一款功放模块&#xff0c;供电是3.3~5V&#xff0c;可以使用锂电池供电。模块设计得比较简单&#xff0c;总共3个端口&#xff0c;红色的2.0端子是用来接电源的&#xff0c;另外2个白色的2.0mm端子是用来分布接2个喇叭的&#xff1b;喇叭可以用4欧姆或者2欧姆的…

作者头像 李华
网站建设 2026/10/23 6:10:26

深入解析TCP-RDT2.2:用UDP实现可靠数据传输的核心机制

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华