mcpField
T
test-migration

test-migration

github.com/petrkindlmann测试与质量2221.1k 次安装6 天前更新
代码仓库

关于 test-migration

test-migration 是帮助团队将测试套件逐步迁移到新框架的技能,适用于需要保留现有覆盖率与 CI 安全网的项目。它建议新旧套件并行运行,达到覆盖率和稳定性要求后再移除旧框架。

主要功能

  1. 01按优先级逐步迁移测试
  2. 02新旧测试套件在 CI 并行运行
  3. 03先迁移共享测试基础设施
  4. 04提供框架间模式映射指南
  5. 05使用转换工具进行初步迁移
  6. 06以覆盖率和稳定性判断退役

适用场景

  1. 01将 Selenium 测试迁移至 Playwright
  2. 02将 Cypress 测试迁移至 Playwright
  3. 03将 Jest 或 Mocha 迁移至 Vitest
  4. 04在大型测试迁移中维持 CI 安全网

安装

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

$npx skills add https://github.com/petrkindlmann/qa-skills --skill test-migration

安装后在 Claude Code 中输入/test-migration确认已加载。

附带文件references/framework-guides.mdreferences/parallel-ci.md

详细介绍

框架迁移期间,测试覆盖率很容易悄然流失:二十个旧测试变成十五个新测试,一个不稳定的 Selenium 测试被原样复现成一个不稳定的 Playwright 测试,而旧的安全网测试套件却提前一个迭代周期就被删除了。这项技能通过增量迁移,并让两套测试套件在 CI 中同时运行,直到证明覆盖率一致为止——让新套件凭实力赢得退役资格,而不是只靠你口头断言。

快速导航

你要从 → 迁移到跳转至首轮工具
Selenium → Playwright翻译模式 + references/framework-guides.md手动编写;没有值得信赖的代码转换工具
Cypress → Playwright翻译模式 + references/framework-guides.mdcy2pw 网页转换器/社区 CLI(参见工具表)
Protractor → Playwrightreferences/framework-guides.md(紧急——2023 年终止支持)手动编写;映射 by.model/by.binding
Jest → Vitestreferences/framework-guides.md先用 sed 将 jest.替换为vi.,再验证
Mocha → Vitestreferences/framework-guides.md先用 chai-matcher 代码转换工具,再验证
任意迁移路径,测试数量超过 100 个迁移工作流 + 并行运行策略始终在 CI 中并行运行

调研问题

先检查 .agents/qa-project-context.md。如果该文件存在,请将其作为上下文,并跳过其中已回答的问题。

当前状态:

  • 你要从什么框架迁移到什么框架?(这决定了要使用的翻译表以及适用的指南章节)
  • 有多少个测试,目前的不稳定率/跳过率是多少?(迁移不稳定的测试会复现其不稳定性;可能不值得迁移被跳过的测试)
  • 目前是否有覆盖率数据?(作为对等迁移的基线)

测试基础设施:

  • 有哪些配套基础设施?(页面对象、自定义命令、测试夹具、数据工厂——这些都要先于测试迁移)
  • 如何处理身份验证/会话?(登录流程是最常见的隐性故障点——参见故障模式)
  • 哪条 CI 流水线负责运行测试?两种框架能否同时运行?(并行运行不可妥协)

约束条件:

  • 时间安排有多紧?(紧急情况=框架终止支持,例如 Protractor;时间充裕=现代化改造)
  • 迁移期间同时运行两套测试套件的预算是多少?(CI 成本暂时翻倍)
  • 团队对目标框架的熟悉程度如何?(培训差距决定研讨会/结对计划)

核心原则

1. 增量迁移优于大爆炸式重写

一次性重写所有测试,是风险最高的做法。它会让测试开发停滞数周,一次性提交大量未经验证的测试,并在替代方案尚未就绪前移除已验证的安全网。务必一次迁移一个测试、一个模块。

2. 并行运行,直到覆盖率一致

在 CI 中同时运行两套测试套件,直到新套件的覆盖率至少达到旧套件的水平。旧套件是你的安全网;让它继续存在,但不阻塞流程。只有当新套件在多个迭代周期中捕获到真实回归问题后,才将旧套件退役。

3. 优先迁移价值最高的测试

从关键用户旅程、频繁失败的测试(这些测试最能受益于更好的框架)以及高风险领域入手。低价值测试留到最后——有些根本不值得迁移,这也是合理且应有记录的决定。

4. 迁移时改进模式,而不只是翻译

把糟糕的 Selenium 测试翻译成糟糕的 Playwright 测试,就是浪费机会。对于每个测试,都要问:“如果从头开始用目标框架编写,我会怎么写?”——使用面向用户的定位器、自动等待和测试夹具。对于 AI 代码转换工具的输出,这一点更是尤为重要(参见反模式)。


迁移工作流

典型的多 Sprint 迁移分为六个阶段。请直接使用内嵌清单;复杂代码请参阅参考资料。

阶段 1 — 审查现有测试套件(第 1 周)。 统计各类别的测试数量、跳过/不稳定测试的占比、覆盖率(如有测量)、运行时间、页面对象/工具文件、自定义插件和 CI 阶段。然后为每项测试分类:关键(营收流程)→ 高优先级(核心旅程)→ 中优先级(次要流程)→ 低优先级(管理/边缘场景)→ 跳过(已禁用、重复、过时)。此优先级顺序将决定后续所有工作。

阶段 2 — 设置目标框架(第 1–2 周)。 与旧框架并行安装。创建配置文件(playwright.config.ts / vitest.config.ts)、独立测试目录、非阻塞 CI 阶段、一个用于验证配置的冒烟测试、与现有格式匹配的报告器,以及共享环境变量/密钥。

阶段 3 — 迁移共享基础设施(第 2–3 周)。 先迁移基础设施,再迁移测试,顺序如下:基础页面对象/测试基类 → 身份验证辅助工具 → API 客户端辅助工具 → 通用页面对象(导航栏/页眉/页脚)→ 数据工厂 → 自定义断言 → 功能专属页面对象(及其测试)。在此阶段捕获 storageState,以便迁移后的测试跳过登录流程。

阶段 4 — 按优先级迁移测试(第 3–8 周及以后)。 对每项测试:阅读旧测试并理解它实际验证的内容 → 使用现代模式从头编写新测试(不要逐行翻译)→ 在本地运行并通过 → 在 CI 中运行并通过 → 将旧测试标记为“已迁移”(不要删除)→ 并行运行一个 Sprint 且均通过后,删除旧测试。

阶段 5 — 在 CI 中并行运行(全程)。 每个流水线都会运行两个测试套件。新测试套件达到同等水平前,旧测试套件保持非阻塞(continue-on-error: true);达到后,让新测试套件成为阻塞项,并移除旧任务。完整的 GitHub Actions 工作流请参阅 references/parallel-ci.md。

阶段 6 — 停用旧框架(最后)。 仅在达到同等水平且运行稳定后执行:所有关键/高优先级测试均已迁移,新测试套件在 CI 中连续 2 个以上 Sprint 通过,新测试套件的不稳定程度不高于旧测试套件,覆盖率对比未显示退步,团队已连续 2 个以上 Sprint 使用新框架编写新测试。然后从 package.json 中移除旧依赖,删除旧测试文件(不能只禁用),更新 CI,使其仅运行新测试套件,并更新文档。


自动化迁移工具

没有什么 AI 魔法按钮。请根据迁移路径选择合适的首轮工具,然后参照 references/framework-guides.md 手动完善。

工具适用场景不要依赖它处理
cy2pw web converter (demo.playwright.dev/cy2pw)Cypress→Playwright,适用于简单的测试规格;官方、确定性强,提供浏览器 UI自定义命令、POM 规范、测试夹具设置
@11joselu/cypress-to-playwright(社区 CLI,npx @11joselu/cypress-to-playwright <dir>)对目录中的 Cypress→Playwright 测试进行批量首轮转换任何依赖时序的内容——请逐个检查文件
AI agents(Claude Code、Cursor)自定义命令和测试夹具转换,以及转换器无法处理的部分已完成的测试——只把输出当作首轮结果
Playwright 1.59+ agentic CLI(npx playwright trace、--debug=cli、经过 AI 优化的无障碍快照)迁移之后,排查迁移测试失败的原因迁移本身——这些是调试工具,不是转换器

避免使用: npx playwright migrate——Playwright CLI 并没有这个内置命令;在终端执行该指令会失败(已于 2026 年 6 月验证)。请使用上面的 cy2pw 或社区 CLI。

黄金参考范例方案。 在让任何 AI 或代码转换工具批量处理测试套件前,先手动端到端迁移一项有代表性的测试。将其提交为团队的规范模式(例如 e2e/_golden/login.spec.ts)。将此测试作为少量样例参考提供给 AI,并让人工审查者参照它。之后的每次迁移都以此文件为准——这是确保 AI 输出和审查者保持一致、效果最显著的做法。


转换模式

定位器映射
旧模式新模式(Playwright)说明
By.id('submit-btn')page.getByRole('button', { name: 'Submit' })优先使用基于角色的定位
By.css('.nav-item.active')page.getByRole('link', { name: 'Dashboard' })使用用户可见文本
By.xpath('//div[@class="modal"]')page.getByRole('dialog')ARIA 角色更稳定
By.css('[data-testid="user-menu"]')page.getByTestId('user-menu')将 testid 作为备用方案
cy.get('.product-card').first()page.getByRole('article').first()优先使用语义化元素
cy.contains('Add to cart')page.getByRole('button', { name: 'Add to cart' })使用具体角色更好
element(by.model('username'))page.getByLabel('Username')Angular 模型 → 标签

以上角色和标签名称仅供示例,请替换为应用实际呈现的无障碍名称。

等待策略映射
旧模式新模式(Playwright)说明
Thread.sleep(3000)(完全移除)Playwright 会自动等待
WebDriverWait(driver, 10).until(visible)(完全移除)操作时自动等待
cy.wait(2000)(完全移除)断言时自动等待
cy.wait('@apiCall')page.waitForResponse(/\/api\/data/)显式等待网络响应(在执行操作前启动 Promise)
browser.wait(EC.presenceOf(...))await expect(locator).toBeVisible()以网页为先的断言
implicitlyWait(10, SECONDS)(移除 — 在配置中设置)在配置中使用 actionTimeout
使用轮询的 FluentWaitawait expect(locator).toHaveText('Done')以网页为先的断言会重试
断言映射
旧模式新模式(Playwright)说明
assert element.is_displayed()await expect(locator).toBeVisible()自动重试
cy.get('.msg').should('have.text', 'Done')await expect(locator).toHaveText('Done')自动重试
expect(element.getText()).toBe('Done')await expect(locator).toHaveText('Done')自动重试
cy.url().should('include', '/dashboard')await expect(page).toHaveURL(/dashboard/)自动重试
assert len(elements) == 5await expect(locator).toHaveCount(5)自动重试
配置映射(Cypress → Playwright)
旧版(Cypress)新版(Playwright)
baseUrluse.baseURL
defaultCommandTimeout: 10000use.actionTimeout: 10000
pageLoadTimeout: 30000use.navigationTimeout: 30000
retries: { runMode: 2 }retries: 2
video: trueuse.video: 'on'
screenshotOnRunFailure: trueuse.screenshot: 'only-on-failure'

特定迁移指南

每种迁移路径都有各自的关键差异、迁移前后代码,以及 references/framework-guides.md 中的迁移说明检查清单。快速了解:

  • Selenium → Playwright: 删除所有显式等待(Playwright 会自动等待),将字符串定位器替换为 getByRole/getByLabel/getByTestId,并用 BrowserContext 替换 WebDriver 会话。捕获 storageState,而不是重新实现登录逻辑。
  • Jest → Vitest(目标版本为 Vitest 4.x):API 基本兼容——将 jest. 替换为 vi.,将 jest.config.js 转换为 vitest.config.ts,移除 Babel/ts-jest 转换(但如果使用了 emotion/styled-components 宏等自定义 Babel 插件,请保留对应的 esbuild/SWC 方案)。运行速度预计可提升 2-10 倍。使用 Vitest 4.1 的测试 tags 实现渐进式切换。
  • Cypress → Playwright(目标版本为 PW ≥ 1.50):最大的变化是从命令队列转向 async/await。cy.intercept()+cy.wait() 改为 page.route()+page.waitForResponse();自定义命令改为 fixtures。注意 1.52 版本中 page.route() 的 glob 和 Cookie 标头的破坏性变更(请通过 browserContext.addCookies() 设置 cookies,而不要覆盖标头)。
  • Mocha → Vitest: 几乎可以一对一迁移。describe/it/钩子保持不变;将 chai 匹配器(to.equal→toBe、to.deep.equal→toEqual、to.contain→toContain)和 sinon→vi.fn()/vi.spyOn() 转换即可。
  • Protractor → Playwright: 自 2023 年起已停止维护,需尽快迁移。移除 waitForAngular,将 by.model/by.binding 映射为 getByLabel/getByText/getByTestId,并将 onPrepare 改为 globalSetup。

并行运行策略

迁移期间的覆盖率对比

在电子表格中跟踪新旧测试套件之间的覆盖率一致性,确保没有遗漏。该文档是停用旧测试套件时进行客观检查的依据。

Feature Area     | Old Suite Tests | New Suite Tests | Parity | Notes
Login/Auth       | 8               | 8               | 100%   | Complete
Dashboard        | 12              | 7               | 58%    | In progress
Search           | 6               | 0               | 0%     | Not started
Checkout         | 15              | 15              | 100%   | Complete
User Settings    | 4               | 4               | 100%   | Complete
Admin Panel      | 20              | 0               | 0%     | Low priority
---              | ---             | ---             | ---    |
Total            | 65              | 34              | 52%    | On track for Q2
渐进式切换时间表

对于包含 200 个测试的套件,计划约 10 个迭代:设置和基础设施(迭代 1-2)、关键路径迁移(迭代 3-5,约 50 个测试)、批量迁移(迭代 6-8)、清理和停用(迭代 9-10)。随着一致性逐步提高,旧测试套件会从阻塞变为非阻塞。从迭代 3 开始,所有新测试都只使用新框架编写。

何时删除旧测试

先将旧测试标记为“已迁移”,不要立即删除。只有当新的对应测试已在 CI 中通过 2 周以上,并且人工审核确认没有丢失独有断言时,才删除旧测试。如果旧测试能捕获新测试遗漏的回归问题,请先完善新测试。


反模式

一次性全面迁移

停止所有开发 3 个月,一次性重写所有测试。团队在重写期间无法发布新测试,覆盖率停滞,而且新测试套件直到一次性全部上线后才会在 CI 中得到验证。

解决方法: 采用渐进式迁移并行运行。每个迭代迁移一个模块。在整个迁移期间,两个测试套件都在 CI 中运行。从第一天起,就用新框架编写新测试。

只翻译,不现代化

逐行将 Selenium 测试转换为 Playwright 测试,同时保留显式等待、CSS 选择器和脆弱模式。测试虽然换成了新框架,却保留了所有旧问题。

解决方法: 按目标框架的最佳实践重写每个测试——使用 getByRole 而非 CSS,不使用显式等待,并用 fixtures 替代 beforeEach。迁移是改进每个测试的好机会。

把 AI 代码迁移工具的结果当作最终答案

Cursor、Aider、Continue、Claude Code 和 cy2pw/community 转换器都会进行机械式转换,但质量参差不齐,而且“只翻译,不现代化”的陷阱在它们的输出中会严重十倍。

解决方法: 先在一个文件上运行工具,并与源文件进行差异对比。如果现代化得当,再批量处理其余文件。如果只是翻译,就编写自己的黄金参考文件,并将其作为少样本示例提供给工具。每轮处理后,都要与原测试套件并行运行——如果结果不一致,说明工具出错了;在推广之前先调查原因。

不并行运行

在新套件得到验证之前,就停用旧套件。由于新套件缺少旧套件中已有的一项测试,导致回归问题漏了过去。

修复方法: 达到覆盖一致后,至少在 2 个冲刺周期内于 CI 中运行两个套件。旧套件是低成本的保险。只有在新套件独立捕获到回归问题后,才停用旧套件。

迁移期间丢失覆盖范围

20 个旧测试变成了 15 个新测试,因为“有些测试重复了”——但没人核实被删掉的测试是否覆盖了独有场景。

修复方法: 在覆盖率电子表格中,明确将每个旧测试对应到新测试。如果有旧测试被有意不迁移,请记录原因,并确认其覆盖范围已由其他测试提供。

照搬不稳定的测试

如果 Selenium 中的测试不稳定,而根本原因是测试设计(共享状态、时间假设、非确定性数据),那么它在 Playwright 中也会不稳定。忠实迁移只会复现这种不稳定性。

修复方法: 先诊断不稳定的原因并修复,然后编写包含修复方案的新测试。迁移是修复不稳定问题的最佳时机,因为无论如何都要重写测试。有关运行时逐项测试排查,请参阅 test-reliability。

团队没有接受培训

团队从未使用过 Playwright 就迁移过去,意味着所有工作都会落到骨干成员身上,而其他团队成员无法维护。

修复方法: 开始前组织一场 2 小时的研讨会。为最初迁移的 10 个测试进行结对编程(骨干成员 + 团队成员)。为新框架编写团队风格指南。每个迁移后的测试必须有 2 位或以上审阅者。


故障模式

症状可能原因修复或检查
每次运行时,迁移后的测试都会重新登录/在测试中途丢失会话没有 storageState——登录流程未迁移过来在 globalSetup 中捕获 storageState;每个测试重复使用。cy.setCookie/driver.add_cookie → browserContext.addCookies()
npx playwright migrate 报错“unknown command”没有这样的内置 CLI使用 cy2pw 网页转换器或 @11joselu/cypress-to-playwright
迁移后的拦截规则始终不匹配1.52 的 glob 变更移除了 ?/[]转义这些字符,或将路由改写为正则表达式
route.continue() 上设置的 Cookie 被忽略route.continue() 上的 Cookie 标头从 Cookie 存储区加载,而非使用你的覆盖值通过 browserContext.addCookies() 设置 Cookie
新测试在本地通过,在 CI 中却不稳定照搬了旧的时间假设使用先检查网页状态的 expect(...) 断言替换 waitForTimeout/显式等待
codemod 运行后测试数量减少codemod 静默跳过了不支持的语法提交前,按功能领域将测试数量与覆盖率对照表进行比对

验证

证明迁移后的产物可正常运行——先做最小检查:

  • 迁移后的测试通过: npx playwright test <migrated-file>(或 npx vitest run <migrated-file>)以状态码 0 退出。绿色运行是最低要求,不是终点。
  • 没有测试数量遗漏: 按功能领域将新旧测试数量与覆盖率电子表格进行比对。“新套件测试”列中的数字应与实际运行的数量一致(每个领域运行 npx playwright test --list | wc -l)。
  • 两个套件都在 CI 中运行: 并行运行工作流将旧版任务设为 continue-on-error: true,并将新版任务设为阻断;流水线运行中应同时显示这两个任务。
  • 没有引入回归问题: 在删除任何旧测试之前,新套件须在 CI 中连续至少 2 个冲刺周期保持全绿。

完成标准

  • 已定义迁移范围:哪些测试优先迁移(关键路径)、哪些最后迁移(低优先级),以及哪些测试有意不迁移(每项都需在覆盖率电子表格中记录理由)。
  • 覆盖率对等电子表格中,每个关键/高优先级功能领域的覆盖率均为 100%,且测试数量不低于映射后的旧测试。
  • 两个框架已在 CI 中并行运行至少连续 2 个冲刺,新测试套件全部通过。
  • 已创建迁移回顾文档,记录不稳定性的根本原因、模式改进和团队培训方面的不足。
  • 已彻底移除旧框架:从 package.json 中删除依赖项,删除旧测试文件(不能仅禁用),并更新 CI 配置,使其只运行新测试套件。

参考文件(位于 references/ 中)

  • framework-guides.md — 五种迁移路径的完整迁移前后代码和迁移注意事项检查清单:Selenium→Playwright、Jest→Vitest、Cypress→Playwright、Mocha→Vitest、Protractor→Playwright。
  • parallel-ci.md — GitHub Actions 并行测试套件工作流,用于在迁移期间并行运行新旧框架。

相关技能

  • playwright-automation — Selenium/Cypress/Protractor 迁移的目标框架最佳实践;翻译完成后,可参阅此技能编写符合 Playwright 惯例的代码。
  • cypress-automation — 如果要迁移到 Cypress,或需要了解 Cypress 源框架的详细信息。
  • unit-testing — 深入了解 Jest→Vitest 模式、模拟对象和覆盖率配置。
  • test-reliability — 在运行时修复单个不稳定测试;如果迁移时发现必须分诊处理而非重写的不稳定测试,可使用此技能。
  • selector-drift-recovery — 在同一框架内进行 UI 重构后,批量重新生成选择器;不适用于框架变更。
  • ci-cd-integration — 并行 CI 配置,用于在迁移期间同时运行两个测试套件。
  • qa-metrics — 跟踪迁移进度:测试数量对等情况、不稳定性对比、覆盖率变化。
  • test-strategy — 迁移决策应与整体的跨季度测试策略保持一致。

评论

支持 Markdown