mcpField
M
Matware E2e Runner

Matware E2e Runner

本地服务
github.com/fastslack开发工具720 周前更新

关于 Matware E2e Runner

Matware E2e Runner 是面向开发团队的端到端网页测试工具,测试以 JSON 描述,并可由 AI 创建、执行和调试。它提供并行浏览器池、实时仪表板及 GitHub/GitLab 问题到测试的流程。

主要功能

  1. 01用 JSON 编写测试流程
  2. 02通过 MCP 创建并运行测试
  3. 03并行执行浏览器测试
  4. 04截图与实时仪表板
  5. 05从问题生成并验证测试

适用场景

  1. 01测试登录或结账流程
  2. 02将 GitHub 或 GitLab 问题转为测试
  3. 03在 CI 中并行运行测试

MCP 相关

内置 MCP 服务,向 Claude Code 等 MCP 客户端提供 17 个测试创建、运行与调试工具。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"mtw-e2e-runner": {
"command": "npx",
"args": [
"-y",
"@matware/e2e-runner"
]
}
}
}
启动命令npx -y @matware/e2e-runner

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@matware/e2e-runner1.3.0
ocidocker.io/fastslack/e2e-runner-mcp:1.3.0

工具

15

收录的工具列表 · 更新于 2 周前

参数类型必填说明
allboolean否运行 tests 目录中的所有测试套件
cwdstring否项目根目录的绝对路径。Claude Code 应传入其当前工作目录。
filestring否JSON 测试文件的绝对或相对路径
suitestring否要运行的套件名称(例如 "auth"、"01-login")。带或不带数字前缀均可匹配。
baseUrlstring否覆盖本次运行的基础 URL
retriesnumber否失败测试的重试次数
concurrencynumber否并行工作进程数(默认值来自配置)
failOnNetworkErrorboolean否网络请求失败时(例如 ERR_CONNECTION_REFUSED)使测试失败。默认值:false。
verificationStrictnessenum否视觉验证严格度。strict:不允许有歧义,任何疑问都判定为 FAIL。moderate:合理判断(默认值)。lenient:仅在存在明显矛盾时判定失败。strict | moderate | lenient

详细介绍

English · Español

@matware/e2e-runner

AI 原生的 E2E 测试运行器,可为你编写、运行和调试测试。

npm 版本 node 版本 npm 下载量 Docker 拉取量 GitHub 星标数 许可证 兼容 MCP AI 原生 兼容 OpenCode Agent 技能


E2E Runner 让你无需编写测试代码即可测试 Web 应用。测试采用纯 JSON 编写——而且你甚至不必亲自编写:只要向 Claude Code 提出要求即可。

🎬 提出要求来编写测试,然后观看它运行

测试套件运行时,实时仪表板不断显示截图
套件运行时的实时仪表板——每个步骤都会实时将截图传送到动态信息流。

借助内置的 MCP 服务,创建测试就像对话一样简单——无需查阅文档,也无需记忆语法:

你: 为登录流程创建一个 E2E 测试并运行它。

Claude Code: 编写测试,在真实浏览器中运行,并向你报告结果—— ✅ login-flow 已通过,耗时 2.3s · 截图已保存 · 没有网络错误。

在幕后,Claude 只需编写并运行了以下内容。测试就是 JSON——一份按顺序列出用户操作的清单:

[
  { "name": "login-flow", "actions": [
    { "type": "goto", "value": "/login" },
    { "type": "type", "selector": "#email", "value": "[email protected]" },
    { "type": "type", "selector": "#password", "value": "secret" },
    { "type": "click", "text": "Sign In" },
    { "type": "assert_text", "text": "Welcome back" },
    { "type": "screenshot", "value": "logged-in.png" }
  ]}
]

无需导入、无需 describe/it,也无需构建步骤。只要看得懂就写得出——或者直接提出要求。

连接到 Claude Code(2 条命令):

claude plugin marketplace add fastslack/mtw-e2e-runner
claude plugin install e2e-runner@matware

现在只需说 "为 X 创建一个测试并运行它"——Claude 就能使用 17 个 MCP 工具、斜杠命令和专用 Agent。

使用其他 Agent(Cursor、Codex、Copilot,以及另外 40 多种)?安装技能:npx skills add fastslack/mtw-e2e-runner


📖 目录

章节内容
🚀安装与首次测试npm 设置 · 使用你自己的 Chrome 运行(无需 Docker)、Obscura 或 Docker 池
✨功能一览快速了解功能
✍️编写测试测试格式 · 完整操作目录 · 重试 · 串行 · 模块 · 身份验证 · 钩子
🤖AI 集成Claude Code · OpenCode · 17 个 MCP 工具 · 视觉验证 · 从问题创建测试
📊仪表板与洞察实时仪表板 · 学习系统 · 网络日志 · 截图捕获
🌐浏览器驱动程序browserless · cdp · lightpanda · obscura · steel
⚙️CLI、配置与 CI命令 · 标志 · e2e.config.js · GitHub Actions · 编程式 API

🚀 安装 — 小巧轻便

npm install --save-dev @matware/e2e-runner
npx e2e-runner init        # scaffolds e2e/ with a sample test + config

然后选择浏览器的运行方式。除非你想使用并行池,否则无需 Docker:

选项 1 · 使用现有的 Chrome — 无需 Docker ⭐

启动任意带有调试端口的 Chromium 浏览器,然后让运行器连接到它:

google-chrome --headless=new --remote-debugging-port=9222 &   # or brave / chromium / msedge
CHROME_POOL_URL=http://localhost:9222 POOL_DRIVER=cdp npx e2e-runner run --all

也可以将其写入 e2e.config.js,这样就不必每次重复设置:

export default {
  baseUrl: 'http://localhost:3000',     // your app — plain localhost, no docker hostname
  poolUrls: ['http://localhost:9222'],
  poolDriver: 'cdp',
};

除 npm 外无需安装任何东西,并且 baseUrl 只需设置为 localhost(浏览器在你的机器上)。

选项 2 · Obscura — 单个轻量二进制文件,无需 Docker

一个约 30 MB 的二进制文件,内置反检测功能。安装一次,运行它,然后让运行器连接到它:

obscura serve --port 9222 --stealth &
CHROME_POOL_URL=http://localhost:9222 POOL_DRIVER=obscura npx e2e-runner run --all

运行 npx e2e-runner pool start(并在配置中设置 poolDriver: 'obscura')会输出适用于你操作系统的确切安装命令。

选项 3 · Docker 池 — 并行运行,适用于 CI 和大型测试套件

一个共享的队列管理型 Chrome 池,可同时运行多项测试:

npx e2e-runner run --all     # the first run auto-starts the Docker pool for you

需要 Docker。设置 baseUrl: 'http://host.docker.internal:3000',这样容器中的 Chrome 才能访问你的应用。

为什么要用 host.docker.internal(仅适用于 Docker 选项)?

使用 Docker 池时,Chrome 在容器内运行,因此其中的 localhost 指的是容器,而不是你的机器。host.docker.internal 可连接到你的主机。在 Linux 上(Docker Engine,而非 Docker Desktop),请添加 --add-host=host.docker.internal:host-gateway,或使用你的局域网 IP。选项 1 和 2 没有这个问题——浏览器在本地运行,因此直接使用 localhost 即可。

编写你的第一个测试

打开 e2e/tests/sample.json — 一个流程是按顺序排列的操作列表:

[
  { "name": "homepage loads", "actions": [
    { "type": "goto", "value": "/" },
    { "type": "assert_text", "text": "Welcome" },
    { "type": "screenshot", "value": "home.png" }
  ]}
]

使用 npx e2e-runner run --all 运行。结果——通过/失败、耗时、屏幕截图、网络错误——会显示在终端中;如果网页控制面板已打开,也会显示在那里。

添加 OpenCode(可选)
cp node_modules/@matware/e2e-runner/opencode.json ./
mkdir -p .opencode && cp -r node_modules/@matware/e2e-runner/.opencode/* .opencode/

详情请参阅 OPENCODE.md。

更新

每种安装方式都需单独更新 — 更新你使用的方式:

# npm dependency (per project)
npm install --save-dev @matware/e2e-runner@latest

# Claude Code plugin
claude plugin update e2e-runner@matware

# MCP-only install (npx caches the package — pin @latest to force a refresh)
claude mcp add --transport stdio --scope user e2e-runner \
  -- npx -y -p @matware/e2e-runner@latest e2e-runner-mcp

说明

有两个注意事项:(1) npx 优先使用项目 node_modules 中的副本,而不是自己的缓存 — 如果项目固定使用旧版本,MCP 服务和控制面板也会运行旧版本,因此还要更新项目依赖项。(2) 已在运行的进程会将旧代码保留在内存中:更新后,重启控制面板并重新连接 MCP 服务(/mcp → e2e-runner → 重新连接,或重启会话)。


✨ 你将获得

🧪 零代码测试 — 使用团队中的任何人都能读写的 JSON 文件。无需 JavaScript,无需编译,也不会被某个框架绑定。

🤖 AI 驱动的测试 — Claude Code 可通过 17 个 MCP 工具原生创建、执行和调试测试。只需让它“测试结账流程”,它就会生成 JSON、运行测试并汇报结果。

🐛 从问题到测试的工作流 — 粘贴 GitHub 或 GitLab 问题的 URL。运行器会获取问题内容、生成端到端测试、运行测试,并告诉你:已确认 Bug 或 无法复现。

👁️ 视觉验证 — 用通俗的语言描述页面应呈现的样子。AI 会截取屏幕截图,并根据你的描述判断通过或失败。无需设置像素差异检测。

🧠 学习系统 — 跟踪测试在多次运行中的稳定性。检测不稳定的测试、不稳定的选择器、缓慢的 API 和错误模式,然后提供可执行的见解。

⚡ 并行执行 — 使用共享浏览器池(browserless、raw CDP、Lightpanda、Obscura 或 Steel)同时运行 N 个测试。对于共享状态的测试,也提供串行模式。

🎯 可插拔的浏览器驱动程序 — 为每个测试选择合适的引擎:通过 browserless 使用真实的 Chrome,使用 Lightpanda 或 Obscura 快速轻量地运行,或使用 Steel 管理会话。可按测试设置 driver,也可以用 --driver 覆盖整个运行过程。

📊 实时仪表板 — 实时执行视图、包含通过率图表的运行历史记录、支持基于哈希搜索的屏幕截图图库,以及可展开的网络请求日志。

🔁 智能重试 — 支持测试级和操作级重试,并可配置延迟。系统会自动检测并标记不稳定的测试。

📦 可复用模块 — 将常见流程(登录、导航、设置)提取为参数化模块,并通过 $use 引用。

🏗️ 适用于 CI — 支持 JUnit XML 输出、失败时返回退出码 1,并自动截取错误屏幕截图。附带可直接使用的 GitHub Actions 示例。

🌐 多项目支持 — 一个仪表板汇总所有项目的测试结果。一个 Chrome 池即可供所有项目使用。

🐳 可移植 — Chrome 在 Docker 中运行,测试以 JSON 文件形式存放在你的代码仓库中。可在任何安装了 Node.js 和 Docker 的机器上运行。


✍️ 编写测试

涵盖测试编写的所有内容——文件格式、完整的操作词汇表、重试、状态隔离和复用。展开所需内容:

测试格式与文件布局

e2e/tests/ 中的每个 .json 文件都包含一个测试数组。每个测试都有一个 name 和按顺序执行的 actions:

[
  {
    "name": "homepage-loads",
    "actions": [
      { "type": "goto", "value": "/" },
      { "type": "assert_visible", "selector": "body" },
      { "type": "assert_url", "value": "/" },
      { "type": "screenshot", "value": "homepage.png" }
    ]
  }
]

套件文件可使用数字前缀来排序(01-auth.json、02-dashboard.json)。--suite 标志无论是否带前缀都能匹配,因此 --suite auth 会找到 01-auth.json。

操作目录 — 导航、输入与交互
| 操作 | 字段 | 描述 | |--------|--------|-------------| | `goto` | `value` | 导航至 URL(相对于 `baseUrl` 或绝对地址) | | `click` | `selector` 或 `text` | 通过 CSS 选择器或可见文本内容点击。文本模式还可使用 `scope: "dialog"`、`visible: true`、`last: true` | | `type` / `fill` | `selector`、`value` | 清空字段并输入文本 | | `wait` | `selector`、`text`、`gone` 或 `value`(毫秒) | 等待元素或文本出现,等待 `gone` 指定的元素消失(如加载指示器或对话框),或固定延时。优先使用条件,而非固定的 `value` 等待时间 | | `screenshot` | `value`(文件名) | 截取屏幕截图 | | `select` | `selector`、`value` | 选择下拉选项 | | `clear` | `selector` | 清空输入字段 | | `press` | `value` | 按下键盘按键(`Enter`、`Tab` 等) | | `scroll` | `selector` 或 `value`(像素) | 滚动至元素或按像素滚动 | | `hover` | `selector` | 将鼠标悬停在元素上 | | `evaluate` | `value` | 在浏览器上下文中执行 JavaScript | | `navigate` | `value` | 浏览器导航(`back`、`forward`、`reload`) | | `clear_cookies` | — | 清除当前页面的所有 Cookie | | `wait_network_idle` | 可选的 `value`(空闲毫秒数,默认 500)、`timeout` | 等待网络空闲达到 `value` 毫秒——适用于会触发后台请求的操作之后 | | `set_storage` | `value`(`"key=val"`),可选的 `selector: "session"` | 设置 `localStorage` 键(或使用 `selector: "session"` 设置 `sessionStorage`) | | `gql` | `value`(查询),可选的 `text`(变量 JSON),可选的 `selector`(断言) | 通过页面内的 `fetch` 运行 GraphQL 查询/变更,并从 `localStorage` 读取身份验证令牌。遇到 GraphQL 错误时失败。`selector` 是针对响应 `r` 执行断言的 JS 表达式(例如 `"r.data.users.length > 0"`)。会安装 `window.__e2eGql`,供后续 `evaluate` 步骤使用 |

按文本点击 — 当 click 使用 text 而非 selector 时,它会搜索常见的交互元素和内容元素:

button, a, [role="button"], [role="tab"], [role="menuitem"], [role="option"],
[role="listitem"], div[class*="cursor"], span, li, td, th, label, p, h1-h6
{ "type": "click", "text": "Sign In" }
断言 — 验证文本、元素、URL、数量和网络
| 操作 | 字段 | 描述 | |--------|--------|-------------| | `assert_text` | `text` | 断言页面任意位置存在该文本(子字符串) | | `assert_no_text` | `text` | 断言页面任意位置均未出现该文本——与 `assert_text` 相反 | | `assert_text_in` | `selector`、`text`、可选的 `value: "exact"` | 断言指定容器内存在该文本。默认情况下,`text` 是不区分大小写的正则表达式;`value: "exact"` 会切换为区分大小写的子字符串匹配 | | `assert_element_text` | `selector`、`text`、可选的 `value: "exact"` | 断言元素文本包含预期文本(或与其完全匹配) | | `assert_url` | `value` | 断言当前 URL 路径或完整 URL。路径(`/dashboard`)仅与 pathname 比较 | | `assert_visible` | `selector` | 断言元素存在且可见 | | `assert_not_visible` | `selector` | 断言元素已隐藏或不存在 | | `assert_attribute` | `selector`、`value` | 检查属性:`"type=email"` 用于检查值,`"disabled"` 用于检查属性是否存在 | | `assert_class` | `selector`、`value` | 断言元素具有指定的 CSS 类 | | `assert_input_value` | `selector`、`value` | 断言输入框、选择框或文本区域的 `.value` 包含指定文本 | | `assert_matches` | `selector`、`value`(正则表达式) | 断言元素文本与正则表达式模式匹配 | | `assert_count` | `selector`、`value` | 断言元素数量:精确值(`"5"`)或运算符(`">3"`、`">=1"`、`"<10"`) | | `assert_no_network_errors` | — | 如果任何网络请求失败(例如 `ERR_CONNECTION_REFUSED`),则失败 | | `assert_storage` | `value`(`"key"` 或 `"key=expected"`)、可选的 `selector: "session"` | 断言 `localStorage`/`sessionStorage` 键存在或具有指定值 | | `assert_visual` | `value`(基准图片)、可选的 `selector`、`text`(最大差异,例如 `"0.02"`)、`fullPage`、`maskRegions`、`threshold` | 视觉回归:将屏幕截图与基准图片进行比较。首次运行时保存基准图片;之后如果差异像素超过阈值(默认为 2%),则运行失败并生成差异图片 | | `get_text` | `selector` | 提取元素文本(非断言,不会失败)。结果:`{ value: "..." }` |
框架感知操作 — 无需编写繁琐的 evaluate 样板代码,即可用于 React/MUI

这些操作可处理 React/MUI 应用中的常见模式,而这些模式通常需要编写冗长的 evaluate 样板代码:

操作字段描述
type_reactselector、value、可选的 blur、waitAfter使用原生值设置器向 React 受控输入框输入内容。会分发 input 和 change 事件,确保 React 状态正确更新。blur: true 会在失焦时提交;waitAfter: "<ms>" 会在操作后等待(适用于防抖自动补全)。
click_regextext(正则表达式)、可选的 selector、可选的 value: "last"点击 textContent 与正则表达式匹配的元素(不区分大小写)。默认点击第一个匹配项。使用 value: "last" 点击最后一个匹配项。
click_optiontext根据文本点击 [role="option"] 元素——常见于自动补全/选择下拉菜单。
select_comboboxtext、可选的 selector、filter、openWait/filterWait/waitAfter打开 MUI Autocomplete/Select,可选择输入 filter,然后点击与 text 匹配的选项。会依次尝试匹配 [role="option"]、.MuiAutocomplete-option、li.MuiMenuItem-root。
focus_autocompletetext(标签文本)根据标签文本聚焦自动补全输入框。支持 MUI 和通用的 [role="combobox"]。
click_chiptext根据文本点击芯片/标签元素。会搜索 [class*="Chip"]、[class*="chip"]、[data-chip]。
click_iconvalue(图标 ID)、可选的 selector(范围)根据 data-testid/data-icon/aria-label/类名片段或 SVG <title> 点击图标——支持 MUI、FontAwesome、Heroicons 等。会点击最近的可点击祖先元素(按钮、链接、标签页)。
click_menu_itemtext、可选的 selector(范围)根据文本点击菜单项,支持 [role="menuitem"]、.dropdown-item、.menu-item、MUI MenuItem。
click_in_contexttext(容器文本)、selector(子元素)在与 text 匹配的最小容器内点击子元素——例如某个特定卡片/行中的删除按钮。
// Before: 5 lines of evaluate boilerplate
{ "type": "evaluate", "value": "const input = document.querySelector('#search'); const nativeSet = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set; nativeSet.call(input, 'term'); input.dispatchEvent(new Event('input', {bubbles: true})); input.dispatchEvent(new Event('change', {bubbles: true}));" }

// After: 1 action
{ "type": "type_react", "selector": "#search", "value": "term" }
多标签页操作 — 弹出窗口、OAuth 窗口和跨标签页流程
操作字段描述
open_tabvalue(URL)、可选的 text(标签)打开新标签页并导航到该 URL(相对于 baseUrl 或绝对 URL)。标签默认为 tab-<n>
switch_tabvalue根据标签、数字索引或标题/URL 匹配项(正则表达式或子字符串)切换活动标签页。"default" 返回原始标签页
wait_for_tab可选的 text(标签)、timeout等待应用打开新标签页/弹出窗口(window.open、target="_blank"),并将其设为活动标签页
assert_tab_countvalue断言打开的标签页数量:精确值("2")或运算符(">=2")
close_tab可选的 value(标签)关闭当前标签页(或指定标签页),并切换回最后一个剩余标签页

之后的所有操作都会在活动标签页中运行:

{ "type": "click", "text": "Open report" }
{ "type": "wait_for_tab", "text": "report" }
{ "type": "assert_text", "text": "Quarterly results" }
{ "type": "close_tab" }
重试与不稳定检测

测试级重试 — 失败时重试整个测试。可通过配置全局设置,也可按测试设置:

{ "name": "flaky-test", "retries": 3, "timeout": 15000, "actions": [...] }

重试后通过的测试会在报告和学习系统中标记为不稳定。

操作级重试 — 重试单个操作,而无需重新运行整个测试。适用于对时序敏感的点击和等待:

{ "type": "click", "selector": "#dynamic-btn", "retries": 3 }
{ "type": "wait", "selector": ".lazy-loaded", "retries": 2 }

可通过配置中的 actionRetries、CLI 参数 --action-retries <n> 或环境变量 ACTION_RETRIES 进行全局设置。重试间隔:actionRetryDelay(默认值为 500ms)。

串行测试 — 适用于共享状态的测试

共享状态的测试(例如,两个测试修改同一条记录)在并行运行时可能发生竞争。可将这些测试标记为串行:

{ "name": "create-patient", "serial": true, "actions": [...] }
{ "name": "verify-patient-list", "serial": true, "actions": [...] }

串行测试会在所有并行测试完成后逐个运行——避免相互干扰,同时不降低独立测试的速度。

测试经过身份验证的应用

最简单的方法——像真实用户一样通过 UI 登录:

{
  "hooks": {
    "beforeEach": [
      { "type": "goto", "value": "/login" },
      { "type": "type", "selector": "#email", "value": "[email protected]" },
      { "type": "type", "selector": "#password", "value": "test-password" },
      { "type": "click", "text": "Sign In" },
      { "type": "wait", "selector": ".dashboard" }
    ]
  },
  "tests": [...]
}
对于使用 JWT 的 SPA,可直接注入令牌来跳过登录表单:
{ "type": "set_storage", "value": "accessToken=eyJhbGciOiJIUzI1NiIs..." }

也可以在配置中全局设置:

// e2e.config.js
export default {
  authToken: 'eyJhbGciOiJIUzI1NiIs...',
  authStorageKey: 'accessToken',
};

每项测试都会在全新的浏览器上下文中运行,因此测试之间的身份验证状态会自动清理。

**更多策略:**基于 Cookie 的身份验证、HTTP 标头注入、绕过 OAuth/SSO、可复用身份验证模块以及基于角色的测试,请参阅 docs/authentication.md

可复用模块 — 使用 $use 提取常见流程

将常见流程提取为带参数的模块:

// e2e/modules/login.json
{
  "$module": "login",
  "description": "Log in via the UI login form",
  "params": {
    "email": { "required": true, "description": "User email" },
    "password": { "required": true, "description": "User password" }
  },
  "actions": [
    { "type": "goto", "value": "/login" },
    { "type": "type", "selector": "#email", "value": "{{email}}" },
    { "type": "type", "selector": "#password", "value": "{{password}}" },
    { "type": "click", "text": "Sign In" },
    { "type": "wait", "value": "2000" }
  ]
}

在测试中使用:

{
  "name": "dashboard-loads",
  "actions": [
    { "$use": "login", "params": { "email": "[email protected]", "password": "secret" } },
    { "type": "assert_text", "text": "Dashboard" }
  ]
}

模块支持参数验证(缺少必需参数时会立即失败)、条件块({{#param}}...{{/param}})、嵌套组合和循环检测。

钩子 — beforeAll / beforeEach / afterEach / afterAll

在生命周期的各个阶段运行操作。可在配置中全局定义,也可按测试套件定义:

{
  "hooks": {
    "beforeAll": [{ "type": "goto", "value": "/setup" }],
    "beforeEach": [{ "type": "goto", "value": "/" }],
    "afterEach": [{ "type": "screenshot", "value": "after.png" }],
    "afterAll": []
  },
  "tests": [...]
}

重要:beforeAll 会在单独的浏览器页面中运行,该页面会在测试开始前关闭。对于测试所需的状态(Cookie、本地存储、身份验证令牌),请使用 beforeEach。

排除模式 — 在 --all 中跳过草稿

在 --all 运行中跳过探索性测试或草稿测试:

// e2e.config.js
export default {
  exclude: ['explore-*', 'debug-*', 'draft-*'],
};

单独运行测试套件(--suite)不受排除模式影响。


🤖 AI 集成

核心理念:由你的 Agent 为你编写、运行并验证测试。

Claude Code — 安装插件和仅安装 MCP
claude plugin marketplace add fastslack/mtw-e2e-runner
claude plugin install e2e-runner@matware

这会为 Claude 提供 17 个 MCP 工具、一个工作流技能、4 个斜杠命令(/e2e-runner:run、/e2e-runner:create-test、/e2e-runner:verify-issue、/e2e-runner:capture),以及 3 个专用 Agent(test-analyzer、test-creator、test-improver)。

仅安装 MCP(仅工具,不含技能/命令/Agent):

claude mcp add --transport stdio --scope user e2e-runner \
  -- npx -y -p @matware/e2e-runner e2e-runner-mcp
OpenCode
cp node_modules/@matware/e2e-runner/opencode.json ./
mkdir -p .opencode && cp -r node_modules/@matware/e2e-runner/.opencode/* .opencode/

详情请参阅 OPENCODE.md。

17 个 MCP 工具
工具描述
e2e_run运行测试(全部、按测试套件或按文件)
e2e_list列出可用的测试套件
e2e_create_test创建新的测试 JSON 文件
e2e_create_module创建可复用模块
e2e_pool_status检查 Chrome 池的运行状况
e2e_app_pool_status检查应用环境池(分支、端口、驱动程序)
e2e_screenshot根据哈希值获取截图
e2e_capture截取任意 URL 的页面
e2e_analyze提取页面结构(交互元素、表单、标题),并生成测试脚手架
e2e_dashboard_start启动 Web 仪表板
e2e_dashboard_stop停止 Web 仪表板
e2e_dashboard_restart重启仪表板(新的项目目录/端口,清除过期会话)
e2e_issue获取问题并生成测试
e2e_network_logs查询某次运行的网络日志
e2e_learnings查询稳定性洞察
e2e_vars管理由 SQLite 提供支持的 {{var.KEY}} 项目变量
e2e_neo4j管理 Neo4j 知识图谱

池的启动/停止仅支持通过 CLI 操作,不通过 MCP 提供。

视觉验证 — 描述页面,由 AI 判定

描述页面应呈现的样子,AI 会根据截图判定通过或失败:

{
  "name": "dashboard-loads",
  "expect": "Patient list with at least 3 rows, no error messages, sidebar with navigation links",
  "actions": [
    { "type": "goto", "value": "/dashboard" },
    { "type": "wait", "selector": ".patient-list" }
  ]
}

测试操作完成后,运行器会自动截取验证截图。MCP 响应中包含截图哈希值,Claude Code 会获取截图,并根据你的 expect 描述进行视觉验证。无需 API 密钥。

从问题生成测试 — 将 Bug 报告转为可运行的测试

将 GitHub 和 GitLab 问题转为可执行的 E2E 测试。粘贴问题 URL,即可自动获取可运行的测试。

工作原理:

  1. 获取 — 通过 gh 或 glab CLI 拉取问题详情(标题、正文、标签)
  2. 生成 — AI 根据问题描述创建 JSON 测试操作
  3. 运行 — 可选择立即执行测试,以验证 Bug 是否可复现
# Fetch and display
e2e-runner issue https://github.com/owner/repo/issues/42

# Generate a test file via Claude API
e2e-runner issue https://github.com/owner/repo/issues/42 --generate

# Generate + run + report
e2e-runner issue https://github.com/owner/repo/issues/42 --verify
# -> "BUG CONFIRMED" or "NOT REPRODUCIBLE"

在 Claude Code 中,只需提出请求:

“获取问题 #42 并为其创建 E2E 测试”

Bug 验证逻辑:生成的测试会断言正确行为。测试失败 = 确认存在 Bug。所有测试通过 = 无法复现。

**身份验证:**GitHub 需要 gh CLI,GitLab 需要 glab CLI。支持自托管的 GitLab。


📊 仪表板与洞察

e2e-runner dashboard                  # Start on default port 8484
e2e-runner dashboard --port 9090      # Custom port
Web 仪表板介绍 — 实时视图、历史记录、图库、池状态

实时执行 — 实时监控测试,查看逐步进度、耗时和活跃工作器数量。

仪表板 - 实时测试执行

测试套件 — 浏览各项目中的所有测试套件。只需单击一下,即可运行单个测试套件或所有测试。

仪表板 - 测试套件网格

**运行历史** — 使用内置图表追踪通过率趋势。点击任意行可展开完整详情。

仪表板 - 运行历史

运行详情 — PASS/FAIL 徽标、可复制哈希值(ss:77c28b5a)的截图缩略图、格式化的控制台错误和网络请求日志。

仪表板 - 运行详情

截图库 — 浏览所有捕获的截图并按哈希搜索(操作、错误和验证截图)。

仪表板 - 截图库

池状态 — Chrome 池健康状况:可用槽位、运行中的会话和内存压力。

仪表板 - 池状态

学习系统 — 不稳定测试、不稳定选择器、缓慢的 API

运行器会从每次测试运行中学习,逐步积累有关测试套件的知识。通过 e2e_learnings MCP 工具查询洞察:

查询返回内容
summary完整的健康状况概览:通过率、不稳定测试、不稳定选择器、API 问题
flaky仅在重试后通过的测试
selectors失败率较高的 CSS 选择器
pages存在控制台错误、网络故障或加载时间问题的页面
apis存在错误率和延迟问题的 API 端点(自动规范化:UUID、哈希值、ID)
errors按类别整理的最常见错误模式
trends随时间变化的通过率(当所有数据都来自同一天时,自动切换为按小时统计)
test:<name>特定测试的历史详情
page:<path>特定页面的历史详情
selector:<value>特定选择器的历史详情

存储与导出:

  • SQLite(~/.e2e-runner/dashboard.db)——默认选项,无需设置
  • Neo4j 知识图谱——可选,用于基于关系的分析。通过 e2e_neo4j MCP 工具或 docker compose 管理
  • Markdown 报告(e2e/learnings.md)——每次运行后自动生成

测试叙述: 每次测试运行都会生成按步骤描述执行过程的易读说明,可在 CLI 输出和仪表板中查看。

网络错误处理 — 断言、全局标志、完整日志

显式断言 — 在关键页面加载后放置 assert_no_network_errors:

{ "type": "goto", "value": "/dashboard" },
{ "type": "wait", "selector": ".loaded" },
{ "type": "assert_no_network_errors" }

全局标志 — 设置 failOnNetworkError: true,自动使任何出现网络错误的测试失败:

e2e-runner run --all --fail-on-network-error

禁用时(默认),运行器仍会收集并报告网络错误——如果测试通过但存在网络错误,MCP 响应中会包含警告。

完整网络日志 — 捕获所有 XHR/fetch 请求,包括 URL、方法、状态、耗时、请求/响应标头和响应正文(截断至 50KB)。可在仪表板中查看,并可展开请求详情行。

MCP 深入查询流程:

1. e2e_run          → compact networkSummary + runDbId
2. e2e_network_logs(runDbId)                     → all requests (url, method, status, duration)
3. e2e_network_logs(runDbId, errorsOnly: true)   → only failed requests
4. e2e_network_logs(runDbId, includeHeaders: true) → with headers
5. e2e_network_logs(runDbId, includeBodies: true)  → full request/response bodies

无论捕获了多少请求,e2e_run 响应都保持精简(约 5KB)。使用返回的 runDbId 调用 e2e_network_logs,按需深入查看详情。

截图捕获 — 按需截取任意 URL

按需截取任意 URL 的屏幕截图——无需测试套件:

e2e-runner capture https://example.com
e2e-runner capture https://example.com --full-page --selector ".loaded" --delay 2000

通过 MCP,e2e_capture 工具支持用于身份验证页面的 authToken 和 authStorageKey——它会在导航前将令牌注入 localStorage。 每张截图都会获得一个确定性哈希(ss:a3f2b1c9)。使用 e2e_screenshot 按哈希检索任意截图 — 它会返回附带元数据(测试名称、步骤、类型)的图像。


🌐 浏览器驱动

运行器可以通过不同驱动与多个浏览器引擎交互。默认值为 auto — 它会探测每个池 URL,并为每个池选择合适的驱动。

驱动引擎探测方式适用场景
browserless通过 browserless 使用真实 Chromium/pressure 返回 JSON默认选项。生产级 JS 执行、屏幕录制、完整 Chrome 行为
cdp通用 CDP 兼容引擎(原始 Chrome 等)可访问 /json/version其他 CDP 服务都不适用时的备用选项
lightpandaLightpanda(Zig)/json/version 的 Browser=lightpanda速度约快 9×,内存占用约为无头 Chrome 的 1/16 — 非常适合高吞吐量的抓取类测试
obscuraObscura(Rust + V8)/json/version 的 Browser=obscura内存占用约 30 MB,内置反检测(--stealth),通过 Puppeteer 保持与真实 Chrome 接近的表现
steelSteel Browser/v1/sessions 返回 JSON托管会话生命周期,用于编排的 REST API
为每项测试选择驱动 / 为整个运行强制指定驱动
{
  "tests": [
    {
      "name": "checkout flow (heavy JS, real Chrome)",
      "driver": "browserless",
      "actions": [...]
    },
    {
      "name": "scrape product page (lightweight)",
      "driver": "obscura",
      "fallbackDriver": "cdp",
      "actions": [...]
    }
  ]
}

driver 是可选项。设置后,只有检测到的驱动与之匹配的池才会成为候选项。fallbackDriver 必须显式选择启用 — 否则,缺少目标驱动时,测试会以清晰的提示失败。池的繁忙状态不会触发回退;运行器会在筛选后的候选池中等待。

为整个运行强制指定驱动(CLI 参数优先于单项测试字段 — 适用于 A/B 基准测试):

e2e-runner run --all --driver obscura
e2e-runner run --all --driver obscura --fallback-driver cdp
在本地运行各驱动
# browserless (default) — managed by `pool start`
e2e-runner pool start

# Lightpanda — pool start uses templates/docker-compose-lightpanda.yml
e2e-runner pool start                 # with poolDriver: 'lightpanda' in config

# Obscura — install the binary and run it yourself
curl -LO https://github.com/h4ckf0r0day/obscura/releases/latest/download/obscura-x86_64-linux.tar.gz
tar xzf obscura-x86_64-linux.tar.gz
./obscura serve --port 9222 --stealth
# then point the runner at it: poolUrls: ['http://localhost:9222'], poolDriver: 'obscura'

⚙️ CLI、配置与 CI

CLI 命令
# Run tests
e2e-runner run --all                  # All suites
e2e-runner run --suite auth           # Single suite
e2e-runner run --tests path/to.json   # Specific file
e2e-runner run --inline '<json>'      # Inline JSON

# Pool management (CLI only, not MCP)
e2e-runner pool start                 # Start Chrome container
e2e-runner pool stop                  # Stop Chrome container
e2e-runner pool status                # Check pool health

# Issue-to-test
e2e-runner issue <url>                # Fetch issue
e2e-runner issue <url> --generate     # Generate test via AI
e2e-runner issue <url> --verify       # Generate + run + report

# Dashboard
e2e-runner dashboard                  # Start web dashboard

# Other
e2e-runner list                       # List available suites
e2e-runner capture <url>              # On-demand screenshot
e2e-runner init                       # Scaffold project
CLI 选项
标志默认值说明
--base-url <url>http://host.docker.internal:3000应用基础 URL
--pool-url <ws>ws://localhost:3333Chrome 池 WebSocket URL
--concurrency <n>3并行测试工作线程数
--retries <n>0失败测试的重试次数
--action-retries <n>0失败操作的重试次数
--test-timeout <ms>60000单项测试超时时间
--timeout <ms>10000默认操作超时时间
--output <format>json报告格式:json、junit、both
--env <name>default环境配置
--fail-on-network-errorfalse网络错误时使测试失败
--project-name <name>目录名称项目显示名称
--driver <name>(单项测试)为整个运行强制指定池驱动:browserless、cdp、lightpanda、obscura、steel
--fallback-driver <name>无使用 --driver 指定的驱动不可达时显式启用的备用驱动
配置 — e2e.config.js 与优先级

在项目根目录创建 e2e.config.js:

export default {
  baseUrl: 'http://host.docker.internal:3000',
  concurrency: 4,
  retries: 2,
  actionRetries: 1,
  testTimeout: 30000,
  outputFormat: 'both',
  failOnNetworkError: true,
  exclude: ['explore-*', 'debug-*'],

  hooks: {
    beforeEach: [{ type: 'goto', value: '/' }],
  },

  environments: {
    staging: { baseUrl: 'https://staging.example.com' },
    production: { baseUrl: 'https://example.com', concurrency: 5 },
  },
};

配置优先级(从高到低):

  1. CLI 标志
  2. 环境变量
  3. 配置文件(e2e.config.js 或 e2e.config.json)
  4. 默认值

设置 --env <name> 时,匹配的配置会覆盖所有其他设置。

CI/CD — JUnit XML 与 GitHub Actions
e2e-runner run --all --output junit
jobs:
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npx e2e-runner pool start
      - run: npx e2e-runner run --all --output junit
      - uses: mikepenz/action-junit-report@v4
        if: always()
        with:
          report_paths: e2e/screenshots/junit.xml
编程 API
import { createRunner } from '@matware/e2e-runner';

const runner = await createRunner({ baseUrl: 'http://localhost:3000' });

const report = await runner.runAll();
const report = await runner.runSuite('auth');
const report = await runner.runFile('e2e/tests/login.json');
const report = await runner.runTests([
  { name: 'quick-check', actions: [{ type: 'goto', value: '/' }] },
]);

要求

  • Node.js >= 20
  • Docker — 仅 选项 3(并行 Chrome 池)需要。选项 1 和 2 无需 Docker。

许可证

版权所有 2026 Matias Aguirre(fastslack)— Matware

本项目依据 Apache License 2.0 许可证授权。详情请参阅 LICENSE。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。