关于 migrate-to-e2e
用于将受支持的测试运行器套件分批迁移到 e2e 的技能,每批都需验证通过。它指导 Agent 清点测试、搭建运行环境并记录进度,同时由用户决定何时停用旧测试。
主要功能
- 01检测运行器并查阅迁移指南
- 02清点测试套件并记录进度
- 03搭建 e2e 环境并运行冒烟测试
- 04逐步迁移测试与共享辅助代码
- 05检查新旧套件的通过情况
适用场景
- 01逐步迁移 Playwright 或 Cypress 套件
- 02在现有运行器旁搭建 e2e 测试
- 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文件相同。
先检测源运行器,再完整阅读表格对应行中的两份文档,然后清点测试,最后再编写代码。之后的每个步骤都会依赖这两份文档。
| 来源 | 检测依据 | 迁移指南 | 引擎 |
|---|---|---|---|
| Playwright | playwright.config.*、@playwright/test | migrate/playwright | web |
| Cypress | cypress.config.*、cypress/ 文件夹 | migrate/cypress | web |
| Selenium | selenium-webdriver、pom.xml、build.gradle 或 requirements.txt 中的 Selenium | migrate/selenium | web |
| Appium | wdio.conf.* 或测试配置中的 appium: capabilities、package.json 中的 appium、pom.xml 或 build.gradle 中的 io.appium、requirements.txt 中的 Appium-Python-Client | migrate/appium | mobile |
| Detox | .detoxrc*、package.json 中的 detox | migrate/detox | mobile |
| Maestro | 以 appId: 和 --- 开头的 YAML 流程、.maestro/、脚本或工作流中的 maestro test | migrate/maestro | mobile |
| TesterArmy | TesterArmy 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,再到仓库根目录查找。如果找到了,说明这是后续会话:
- 阅读该文件,然后阅读它的
Source行指定的迁移指南和引擎页面。除非用户指定其他切片,否则其Next部分会指定本次会话要处理的切片。 - 对照仓库核实文件内容,确认无误后再依赖它:每个
ported测试仍存在于两个测试套件中;其中列出的每个源文件或测试仍然存在(有意删除的retired项除外);并且没有遗漏任何新增的源文件或测试(将其添加为todo)。如果没有Defect check:行,请按步骤 2 中的说明询问。如果Next下注明了植入的缺陷,请先将其还原(步骤 6)。 - 运行文件中的
Run new命令一次。当前运行失败的已迁移测试是首要修复项,必须先于任何新切片处理。 - 除非进度文件中的
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. 构建测试框架(一次性)
测试框架包括配置、应用启动和一个通过的测试。完成后,进度文件会记录这一点;后续会话会跳过此步骤。
- 如果没有端到端测试配置:运行
npx e2e init --yes(主题为setup);设备项目需加上--engine mobile。删除或改写示例测试。为源测试套件覆盖的每个平台或浏览器配置一个目标。 - 询问用户步骤中使用哪个模型 Agent,并进行配置(主题为
agent)。纯粹移植测试则无需模型:每个测试都可以是确定性的,没有模型的配置也能运行这些测试。 - 移植 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。
- 为应用提供服务的唯一进程(开发服务器、Expo 开发客户端使用的 Metro)将成为目标的
- 使用仓库的包管理器安装软件包,然后运行
npx e2e doctor(e2e 版本为 0.23.0 或更高),并修复所有未通过的检查。此命令会加载配置并检查每个目标的引擎,但不会启动应用:对于 Web 目标,会检查浏览器;对于本地设备移动目标,会检查 agent-device、工具链、设备以及appPath处的构建产物(设备提供方目标会跳过这些检查)。如果在步骤 3.2 中配置了模型,则添加--check-model,以调用每个模型一次。 - 将最简单的源测试(通常是登录或应用启动)移植为冒烟测试。其他测试开始移植前,该测试必须在每个目标上通过。如果无法通过,问题出在测试框架,而不是测试:修复测试框架。
init会添加一个test:e2e脚本(e2e run),除非已有同名脚本。如果该名称已被占用,或未运行init,则使用一个未占用的名称添加脚本。保留旧测试套件的脚本不变。- 在进度文件中标记测试框架已完成,并记录用于启动依赖项、运行旧测试套件和运行新测试套件的命令。
4. 选择切片
切片是指本次会话能够完成并通过测试的范围:一个文件、一个文件夹、一个标签或一个功能区域,通常包含 1 到 5 个测试。询问用户想选择哪一个。如果用户交由你决定,请按以下顺序推荐:
- 共享辅助函数已移植的测试。
- 在旧运行器中经常出问题的测试:重试、CI 中的间歇性故障记录、解释运行器变通方案的注释。这类测试收益最大。
- 需要指南标记为“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)。如果客户端没有e2eMCP 工具,就运行测试并查看其追踪页面上列出的屏幕(主题为debugging);不要搭建桥接。指南中关于选择器的说明列出了大多数移植所需的修改:e2e 会匹配完整字符串,并且匹配到多个结果时会失败,而旧运行器会取第一个。如果查询也匹配到隐藏副本(来自另一种布局),请添加{ visible: true }。如果有两个可见节点匹配,例如第二个 toast 覆盖在第一个上方,请选取与该步骤意图相符的节点。 - 睡眠或固定等待应改为对所等待状态调用
agent.waitFor(agent.waitFor('the upload finished')),或者在定位器名称对应状态或配置中没有模型时,使用带timeout的断言。不要移植等待时长。 - 按平台分支应改为在测试上设置
{ platforms: [...] },或在测试内部对platformfixture 使用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. 证明每个迁移
只有当迁移后的测试与源测试同样严格,且每次运行都通过,才算完成。
- 在源测试覆盖的每个目标上运行:
npx e2e run <file> --repeat-each 3;如果包含 Agent 步骤,还要加上--no-cache。每个目标都必须 3 次全部通过,否则就不算完成(主题running)。 - 如果旧测试套件能在这里运行,就在同一构建上运行源测试。 两个运行器都显示的失败属于应用或环境缺陷:报告该问题,不要通过迁移绕过它。 只有 e2e 显示的失败才属于迁移问题。
- 对照源测试检查严格性:源测试中的每项断言都必须有对应的 e2e
断言,因此断言数量至少要达到清单中的数量,并且必须检查源测试检查过的每个最终状态。绝不能
弱化断言、无故延长超时时间,或删除步骤来让测试通过。无法如实通过的测试应保持为
blocked,并注明失败原因。 - 修改测试前,先阅读任何失败对应的跟踪页面
(主题
debugging)。
缺陷检查(可选)
启用 Defect check: on 时,证明两个套件都会因同一个缺陷而失败:
- 征得用户同意后,在源测试断言过的最终状态中植入一个小缺陷(例如结账页显示了错误的总额),并确保所改文件没有未提交的更改。将该文件记录在
Next下,直到还原为止。 - 重新构建,确认应用显示了该缺陷,然后在相应测试片段上运行
Run old(如果该测试能在这里运行),以及npx e2e run <files> --no-cache。 - 仅还原该文件(
git checkout -- <file>),重新构建,并确认git diff -- <file>为空。 - 两者都在检查植入状态的步骤失败:记录结果。只有旧套件通过:记录源测试较弱。只有 e2e 通过:迁移丢失了断言,因此尚未完成。两者都未失败:选择另一个缺陷。在该步骤之前发生的失败不算捕获到缺陷。
- 填写该行的
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)。 - 不要代替用户提交更改。