mcpField
M
migrate-to-e2e

migrate-to-e2e

github.com/e2e-inc测试与质量13.9k226 次安装今天更新
代码仓库

关于 migrate-to-e2e

用于将受支持的测试运行器套件分批迁移到 e2e 的技能,每批都需验证通过。它指导 Agent 清点测试、搭建运行环境并记录进度,同时由用户决定何时停用旧测试。

主要功能

  1. 01检测运行器并查阅迁移指南
  2. 02清点测试套件并记录进度
  3. 03搭建 e2e 环境并运行冒烟测试
  4. 04逐步迁移测试与共享辅助代码
  5. 05检查新旧套件的通过情况

适用场景

  1. 01逐步迁移 Playwright 或 Cypress 套件
  2. 02在现有运行器旁搭建 e2e 测试
  3. 03跨 Agent 会话继续迁移工作

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/e2e-inc/e2e --skill migrate-to-e2e

安装后在 Claude Code 中输入/migrate-to-e2e确认已加载。

详细介绍

将测试套件迁移到 e2e

迁移绝不是一次性改动。每个会话迁移一部分、验证它,并确保两个套件都通过:旧运行器保留原有的所有测试,新 e2e 测试也能与之并行通过。进度文件 MIGRATION.md 会记录已迁移的内容、剩余工作及其原因,让下一个会话(无论是你还是另一个 Agent)能从这里继续,而不是从头开始。何时移除旧测试,由用户决定。

两份参考文档足以完成大部分工作。请阅读它们;不要复述其中内容。

  • e2e 技能文档,涵盖运行器的所有功能:运行 npx e2e init 或 npx skills add e2e-inc/e2e 后查看 .agents/skills/e2e/SKILL.md,也可以通过已安装的软件包运行 npx e2e guide <topic>。下文提到的主题(setup、writing-tests、agent、mcp、running、debugging)都是该文档的参考文件。
  • 源运行器的迁移指南,以及它所迁移到的引擎页面。指南会将该运行器的配置、命令和 API 映射到 e2e,并说明 e2e 目前尚不支持的内容(标记为“Not yet”、“No equivalent”或 missing)及当前的替代方案。这两份文档都随已安装的软件包提供,位于 node_modules/e2e/docs/ 下,路径与 .mdx 文件相同。

先检测源运行器,再完整阅读表格对应行中的两份文档,然后清点测试,最后再编写代码。之后的每个步骤都会依赖这两份文档。

来源检测依据迁移指南引擎
Playwrightplaywright.config.*、@playwright/testmigrate/playwrightweb
Cypresscypress.config.*、cypress/ 文件夹migrate/cypressweb
Seleniumselenium-webdriver、pom.xml、build.gradle 或 requirements.txt 中的 Seleniummigrate/seleniumweb
Appiumwdio.conf.* 或测试配置中的 appium: capabilities、package.json 中的 appium、pom.xml 或 build.gradle 中的 io.appium、requirements.txt 中的 Appium-Python-Clientmigrate/appiummobile
Detox.detoxrc*、package.json 中的 detoxmigrate/detoxmobile
Maestro以 appId: 和 --- 开头的 YAML 流程、.maestro/、脚本或工作流中的 maestro testmigrate/maestromobile
TesterArmyTesterArmy MCP 工具、MCP 配置中的 testerarmy 条目、脚本或工作流中的 testerarmy 或 tester.army,或用户明确说明migrate/testerarmy根据项目类型选择 web 或 mobile

Web 端的 WebdriverIO 没有迁移指南。请参考 Selenium 指南映射其 WebDriver 调用,并告知用户该映射并不完整。使用 Appium capabilities 的 WebdriverIO 项目属于 Appium 项目。若项目有两个源运行器,应一次迁移一个,并在进度文件中分别记录。

TesterArmy

TesterArmy 测试位于 TesterArmy 中,而非仓库内。请通过 TesterArmy MCP 服务读取测试。如果你的客户端没有 testerarmy 工具,请按照指南中“连接 TesterArmy MCP 服务”一节的说明添加该服务,让用户登录并重启会话,然后等待。

  • 询问要迁移哪个项目(list_projects)。项目的设置、环境、凭据、记忆和文件是测试框架的输入(步骤 3);项目的分组是切片(步骤 4)。
  • 源文件是已保存的测试。其行中的 Source 是测试的标题和 ID,其断言是 assert 步骤。已禁用的测试计为跳过。已禁用的步骤不纳入迁移,也不计数。
  • 只使用读取工具。run_test 和 run_group 会针对已部署的应用启动云端运行:在步骤 6 中,只有得到用户同意后才能调用;否则记录 Run old: not run。不要在 TesterArmy 中创建、更新或删除任何内容;要停用测试,需由用户禁用或删除。
  • TesterArmy 不会返回密码或 TOTP 密钥。请在配置中注明每项凭据,并让用户设置对应的环境变量。
  • 步骤的字面迁移方式是调用 Agent(agent.act、agent.assert),因此配置需要模型(步骤 3.2)。无需判断的步骤应改为定位器调用,具体请参阅指南中的“映射每个步骤”一节。先确认确切名称(步骤 5),并在对应行的 Notes 中注明每项替换。

1. 继续或开始

先在 e2e 配置文件旁查找 MIGRATION.md,再到仓库根目录查找。如果找到了,说明这是后续会话:

  1. 阅读该文件,然后阅读它的 Source 行指定的迁移指南和引擎页面。除非用户指定其他切片,否则其 Next 部分会指定本次会话要处理的切片。
  2. 对照仓库核实文件内容,确认无误后再依赖它:每个 ported 测试仍存在于两个测试套件中;其中列出的每个源文件或测试仍然存在(有意删除的 retired 项除外);并且没有遗漏任何新增的源文件或测试(将其添加为 todo)。如果没有 Defect check: 行,请按步骤 2 中的说明询问。如果 Next 下注明了植入的缺陷,请先将其还原(步骤 6)。
  3. 运行文件中的 Run new 命令一次。当前运行失败的已迁移测试是首要修复项,必须先于任何新切片处理。
  4. 除非进度文件中的 Harness: 行注明 done,否则转到步骤 3,构建测试框架。若已注明,则转到步骤 4,选择切片。

如果没有进度文件,说明是首次会话:执行步骤 2 和 3,然后继续其余步骤。

2. 清点测试套件(首次会话)

根据仓库回答以下问题;只询问用户你无法观察到的信息。

问题答案所在位置决定事项
源运行器上面的检测表本表之前需要阅读的两份文档
测试每个规范、流程或测试文件,以及其中的标题、标签和按平台或浏览器划分的分支。使用运行器自带的列表或试运行模式统计测试数量,不要通过 grep 统计,因为它会漏掉在循环中创建的测试。npx playwright test --list 会为运行该测试的每个项目各列出一次,因此同一个测试即使列在多个项目下,也只统计一次进度文件中的行,每个源文件一行。现在统计每个文件的断言数量,以便检查移植后的数量:明确的断言(expect、should、assertVisible),以及在运行器的步骤本身就是检查的情况下(例如,目标不存在时 Maestro 的 tapOn 会失败),统计这些步骤
共享代码页面对象、自定义命令、子流程(runFlow: file.yaml)、fixture、钩子、globalSetup在第一个需要它们的测试之前,先移植一次这些辅助代码
运行方式运行测试套件的 CI 任务及其调用的脚本:构建、启动的服务和模拟服务器、数据植入和重置调用、env 文件、设备或浏览器、端口端到端测试运行环境。CI 任务通常是唯一完整的说明;请逐行阅读
端到端测试的位置带有 package.json 的 JavaScript 或 TypeScript 项目:其根目录(在 monorepo 中,与源运行器配置文件同级),测试位于 tests/**/*.e2e.ts。原生、Java 或 Python 项目:应用旁边的 e2e/ 文件夹,其中有自己的 package.json。然后查看源运行器的文件匹配模式(testDir、testMatch、specPattern、流程文件夹)端到端测试配置和进度文件的位置。两个运行器不得收集对方的文件:如果匹配模式重叠,请收窄其中一个。Playwright 测试套件通常已将文件命名为 *.e2e.ts,此时目录是唯一的区分方式:Playwright 的 testDir 下不能有端到端测试,端到端测试的 tests glob 下不能有 Playwright 文件。对比 npx playwright test --list 与 npx e2e list
旧测试套件能否在此运行已安装的源运行器、所需的构建、服务决定是否通过运行旧测试(步骤 6)检查一致性,还是仅根据源文本检查

现在编写 MIGRATION.md(格式见步骤 8),将每个源文件标为 todo。

询问每个切片是否也应针对预先植入的缺陷运行(步骤 6),并记录答案:Defect check: on 或 off。

3. 构建测试框架(一次性)

测试框架包括配置、应用启动和一个通过的测试。完成后,进度文件会记录这一点;后续会话会跳过此步骤。

  1. 如果没有端到端测试配置:运行 npx e2e init --yes(主题为 setup);设备项目需加上 --engine mobile。删除或改写示例测试。为源测试套件覆盖的每个平台或浏览器配置一个目标。
  2. 询问用户步骤中使用哪个模型 Agent,并进行配置(主题为 agent)。纯粹移植测试则无需模型:每个测试都可以是确定性的,没有模型的配置也能运行这些测试。
  3. 移植 CI 作业执行的编排逻辑,复用仓库已有脚本,而不要编写新脚本:
    • 为应用提供服务的唯一进程(开发服务器、Expo 开发客户端使用的 Metro)将成为目标的 app.command,并设置 readyUrl(主题为 setup)。该命令只能获取 PATH、HOME、临时目录变量和 command.env,不会获取 shell 的环境变量。因此,需将服务器从旧运行器环境中读取的变量传入 command.env。
    • e2e 没有 services 键。数据库、队列和模拟服务器应在运行前通过 CI 作业使用的命令启动;或者由 app.command 运行一个启动这些服务并提供应用服务的脚本。在进度文件中记录该命令。
    • 源测试在每个测试前执行的重置或播种操作(通过 http.post 使用 runScript、cy.task('db:reset')、beforeEach 中的 API 调用)应改为在 beforeEach 或 fixture 中使用 fetch,以确保每个测试仍从已知数据状态开始。
    • 依赖导入应用自身代码的播种辅助程序(ORM 工厂、服务器模块)应复用,而非重写。旧运行器可能已将其编译为 CommonJS;e2e 会将每个 .ts 文件作为 ES 模块加载。此时在测试中导入它,可能会因 __dirname is not defined、CommonJS 包出现 "does not provide an export named" 错误,或出现 ERR_UNSUPPORTED_DIR_IMPORT 而失败。遇到这些情况时,应使用仓库自带的 TypeScript 运行器(ts-node、tsx)在子进程中原样运行该辅助程序,并从 fixture 中调用它。不要修改应用模块来让它们能够加载。
    • 环境变量值应设为模块常量;密码和令牌应放在 credentials 或 secrets 下(主题为 setup)。如果旧配置通过 dotenv.config() 加载环境文件,则在 e2e 配置中以相同方式加载,以便测试和辅助程序获取相同的值。app.command 无法获取这些值;需将服务器需要的值传入 command.env。
  4. 使用仓库的包管理器安装软件包,然后运行 npx e2e doctor(e2e 版本为 0.23.0 或更高),并修复所有未通过的检查。此命令会加载配置并检查每个目标的引擎,但不会启动应用:对于 Web 目标,会检查浏览器;对于本地设备移动目标,会检查 agent-device、工具链、设备以及 appPath 处的构建产物(设备提供方目标会跳过这些检查)。如果在步骤 3.2 中配置了模型,则添加 --check-model,以调用每个模型一次。
  5. 将最简单的源测试(通常是登录或应用启动)移植为冒烟测试。其他测试开始移植前,该测试必须在每个目标上通过。如果无法通过,问题出在测试框架,而不是测试:修复测试框架。
  6. init 会添加一个 test:e2e 脚本(e2e run),除非已有同名脚本。如果该名称已被占用,或未运行 init,则使用一个未占用的名称添加脚本。保留旧测试套件的脚本不变。
  7. 在进度文件中标记测试框架已完成,并记录用于启动依赖项、运行旧测试套件和运行新测试套件的命令。

4. 选择切片

切片是指本次会话能够完成并通过测试的范围:一个文件、一个文件夹、一个标签或一个功能区域,通常包含 1 到 5 个测试。询问用户想选择哪一个。如果用户交由你决定,请按以下顺序推荐:

  1. 共享辅助函数已移植的测试。
  2. 在旧运行器中经常出问题的测试:重试、CI 中的间歇性故障记录、解释运行器变通方案的注释。这类测试收益最大。
  3. 需要指南标记为“Not yet”“No equivalent”或 missing 的功能的测试,放在最后。

开始前,先将切片写入进度文件的 Next 部分,这样会话中断时也能留下记录。

5. 移植切片

先移植切片的共享辅助函数,只需移植一次,作为普通的 .ts 文件(不要使用 .e2e.ts,以免运行器收集它们),例如放在 tests/support/ 下。子流程改为函数或 test.extend fixture;页面对象改为 fixture(主题为 writing-tests)。将每项记录在进度文件中。

然后一次处理一个测试:

  • 保留测试标题,并在文件开头添加注释,注明来源(// Ported from __e2e__/flows/login.yml),以便在报告和评审中相互对应。
  • 先严格按照指南中的表格逐步直译,每个源步骤对应一次带 await 的调用。每条源断言都对应一条独立的 e2e 断言。超时会失败的等待(waitForFunction)也算一条,因此 e2e 断言数不得少于清单中的数量。
  • 完整移植源代码中跳过的测试,并继续保持跳过状态,同时注明源代码中的原因,这样任一套件都可以重新启用它。对应行应注明这一点;如果原因允许,取消跳过后运行一次并记录结果。
  • 编写定位器前,先了解准确名称:使用 open_session、observe 和 locate 调用 e2e mcp(主题为 mcp)。如果客户端没有 e2e MCP 工具,就运行测试并查看其追踪页面上列出的屏幕(主题为 debugging);不要搭建桥接。指南中关于选择器的说明列出了大多数移植所需的修改:e2e 会匹配完整字符串,并且匹配到多个结果时会失败,而旧运行器会取第一个。如果查询也匹配到隐藏副本(来自另一种布局),请添加 { visible: true }。如果有两个可见节点匹配,例如第二个 toast 覆盖在第一个上方,请选取与该步骤意图相符的节点。
  • 睡眠或固定等待应改为对所等待状态调用 agent.waitFor(agent.waitFor('the upload finished')),或者在定位器名称对应状态或配置中没有模型时,使用带 timeout 的断言。不要移植等待时长。
  • 按平台分支应改为在测试上设置 { platforms: [...] },或在测试内部对 platform fixture 使用 if。
  • 源代码注释中说明的变通方案(不稳定的 hideKeyboard、坐标点击、围绕选择器的重试循环)都是针对旧运行器的变通方案。先尝试直接移植步骤;只有 e2e 也需要时才保留变通方案,并添加单独的注释说明原因。
  • 对于指南标记为“Not yet”“No equivalent”或 missing 的步骤,请使用指南中的变通方案。如果没有变通方案,则测试继续留在旧运行器中:标记为 stays 并注明原因;并只提供一次发送 npx e2e feedback --type feature -m "<the gap>" 的选项:先使用 --dry-run 预览,只有用户同意后才发送(e2e 技能,Feedback)。
  • 不要修改应用代码。如果测试需要应用中不存在的测试 ID,请使用 agent.act 或其他定位器;应向用户提议修改应用,而不是自行修改。缺陷检查中植入的 bug(步骤 6)是例外,须在同一会话中还原。

只有字面移植通过后才能使用 agent.act,不能用它替代字面移植,并且必须配置模型。对于源代码反复打补丁处理的复杂步骤,建议使用它:坐标点击、反复操作选择器、连续长时间点击完成向导。之后立即使用定位器断言确认结果(主题为 agent)。

6. 证明每个迁移

只有当迁移后的测试与源测试同样严格,且每次运行都通过,才算完成。

  1. 在源测试覆盖的每个目标上运行: npx e2e run <file> --repeat-each 3;如果包含 Agent 步骤,还要加上 --no-cache。每个目标都必须 3 次全部通过,否则就不算完成(主题 running)。
  2. 如果旧测试套件能在这里运行,就在同一构建上运行源测试。 两个运行器都显示的失败属于应用或环境缺陷:报告该问题,不要通过迁移绕过它。 只有 e2e 显示的失败才属于迁移问题。
  3. 对照源测试检查严格性:源测试中的每项断言都必须有对应的 e2e 断言,因此断言数量至少要达到清单中的数量,并且必须检查源测试检查过的每个最终状态。绝不能 弱化断言、无故延长超时时间,或删除步骤来让测试通过。无法如实通过的测试应保持为 blocked,并注明失败原因。
  4. 修改测试前,先阅读任何失败对应的跟踪页面 (主题 debugging)。
缺陷检查(可选)

启用 Defect check: on 时,证明两个套件都会因同一个缺陷而失败:

  1. 征得用户同意后,在源测试断言过的最终状态中植入一个小缺陷(例如结账页显示了错误的总额),并确保所改文件没有未提交的更改。将该文件记录在 Next 下,直到还原为止。
  2. 重新构建,确认应用显示了该缺陷,然后在相应测试片段上运行 Run old(如果该测试能在这里运行),以及 npx e2e run <files> --no-cache。
  3. 仅还原该文件(git checkout -- <file>),重新构建,并确认 git diff -- <file> 为空。
  4. 两者都在检查植入状态的步骤失败:记录结果。只有旧套件通过:记录源测试较弱。只有 e2e 通过:迁移丢失了断言,因此尚未完成。两者都未失败:选择另一个缺陷。在该步骤之前发生的失败不算捕获到缺陷。
  5. 填写该行的 Defect check 单元格,例如 total +1: both fail;如果旧套件无法在这里运行,则填 old not run。

7. 运行两个套件

在用户退役某项源测试之前,两个运行器都要保留它。

  • 已迁移的测试也要保留在旧套件中。只有用户确认后才能删除源测试,然后将其标记为 retired。当剩余的源测试和 e2e 代码都不再使用某个源辅助函数后,提出删除它,并在用户确认后删除。
  • CI:有几个迁移已通过后,提议将 e2e 套件添加到旧作业旁边;由于这会修改旧运行器的工作流,只有用户同意后才进行更改。复用其构建、服务和设备。两个运行器绝不能同时控制同一台设备或模拟器;应在同一作业中先后运行,或为每个运行器分配独立设备。e2e 作业会运行每项已迁移的测试,因此之后的更改若导致某项测试失败,拉取请求也会失败(主题 running,Continuous integration)。
  • 当最后一项源测试被标记为 retired 或 stays 时,进度文件应说明迁移已完成,以及(如有)仍保留的测试。

8. 保留进度文件

MIGRATION.md 与 e2e 配置文件放在一起,是迁移状态的记录。随着进展及时更新,不要拖到最后;即使会话中断,文件也必须如实反映当前状态。

# Migration to e2e

Source: Maestro, `__e2e__/flows/**` (guide: https://e2e.com/docs/migrate/maestro.md, engine: https://e2e.com/docs/mobile.md)
e2e: `e2e.config.ts`, tests `tests/**/*.e2e.ts`
Start dependencies: `pnpm e2e:mock-server`
Run old: `maestro test __e2e__`
Run new: `npx e2e run`
Harness: done, smoke `tests/login.e2e.ts` on ios and android
Defect check: on

| Source | e2e | Status | Assertions (source → e2e) | Passing | Defect check | Notes |
| --- | --- | --- | --- | --- | --- | --- |
| flows/login.yml | tests/login.e2e.ts | ported | 3 → 3 | ios 3/3, android 3/3 | wrong screen: both fail | |
| flows/create-account.yml | | blocked | 6 → | | | date picker spin fails on android, trace in .e2e/results |
| flows/search-screen.yml | | todo | 4 → | | | |

## Shared helpers

| Source | e2e | Used by |
| --- | --- | --- |
| setupApp.yml | tests/support/app.ts `openSignedOut()` | login, create-account |

## Gaps

- `addMedia` has no e2e equivalent (guide: Not yet); feedback sent.

## Next

flows/composer.yml and flows/composer-self-label.yml (both need `signInAlice()`).

每个源文件一行。如果一个文件中的测试最终状态不同,则每项测试各占一行,并分别记录断言数量。即使套件包含数百项测试,也仍按文件逐行记录:每次会话开始时都会查看此表。

状态:todo;ported(在 e2e 中通过,源测试仍可运行);retired(用户已确认,源测试已删除);blocked(已尝试,但尚未通过,并注明失败原因);stays(有意保留在旧运行器中,并说明原因)。

9. 交接

告知用户本次会话完成了哪些迁移,以及验证了什么:已迁移的测试及其在各目标上的通过次数、缺陷检查结果、已迁移的辅助函数、哪些内容受阻或保留及其原因、已报告的差距,以及下一批迁移内容。询问哪些标记为 ported 的源测试可以退役。列出创建或更改的每个文件。

规则

  • 每个会话迁移一个切片。保持两个测试套件都通过:旧测试套件像之前一样通过,所有 ported 测试也通过。
  • 未经用户确认,不得删除或编辑源测试、辅助程序或旧测试运行器的配置。
  • 根据仓库内容进行迁移。进度文件中列出的每条命令都至少运行一次;若某条命令无法在此处运行(旧测试运行器未安装),请在进度文件中说明。
  • 如果源步骤的含义不明确,例如点击已禁用的控件,或点击可能未命中的坐标,则在迁移中保留其意图。在进度文件中记录你的理解,并询问用户。
  • e2e 技能或指南中的一句话胜过你自己写的一段话。注明主题或指南的章节。
  • 切勿在测试、配置或进度文件中写入机密。注明凭据(主题为 setup)。
  • 不要代替用户提交更改。

评论

支持 Markdown