migrate-to-e2e について
migrate-to-e2eは、既存のテストスイートを小さな単位で検証しながらe2eへ移行するエージェントスキルです。旧スイートを維持し、`MIGRATION.md`で進捗を記録し、ランナー別の移行ガイドに沿って移植します。
主な機能
- 01対応する既存テストランナーの検出
- 02テストと実行環境の棚卸し
- 03e2eハーネスの構築と検証
- 04小さな単位でのテスト移植
- 05`MIGRATION.md`による進捗管理
活用シーン
- 01Playwrightスイートの段階的な移行
- 02CypressまたはSeleniumテストの移植
- 03DetoxまたはMaestroテストのe2eへの移行
- 04複数セッションにまたがる移行作業の再開
MCP 対応
このスキルは、テスト移植時に`open_session`、`observe`、`locate`などのe2e MCPツールでアプリを調べ、ロケーターを特定する手順を示します。クライアントにツールがない場合は、テストを実行してトレースページを確認します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ tester-army/ e2e --skill migrate-to-e2eインストール後、Claude Code で/migrate-to-e2eを入力して読み込まれたか確認します。
詳細
e2e へのスイート移行
移行は一度に完了するものではありません。セッションごとに一部分を移植して検証し、両方のスイートを正常な状態に保ちます。つまり、旧ランナーには既存のすべてのテストを残し、新しい e2e テストも並行してパスさせます。進捗ファイル MIGRATION.md には、移行した内容、残っている内容、その理由を記録します。これにより、次のセッションでは、自分でも別のエージェントでも、ゼロからではなくこのファイルを起点に作業できます。旧テストをいつ削除するかはユーザーが決めます。
作業の大部分は、2つの参考資料でまかなえます。読んでください。内容を言い換える必要はありません。
- ランナーの動作全般については、e2e スキルを参照してください。
npx e2e initまたはnpx skills add tester-army/e2eの実行後は.agents/skills/e2e/SKILL.mdを、またはインストール済みパッケージからnpx e2e guide <topic>を実行してください。以下に記載のトピック(setup、writing-tests、agent、mcp、running、debugging)は、スキルの参考ファイルです。 - 移行元ランナーの移行ガイドと、移行先のエンジンページを参照してください。移行ガイドでは、ランナーの設定、コマンド、API を e2e に対応付け、e2e にまだない機能(
missingまたは「No equivalent」と記載)と、現在の回避策を説明しています。どちらもインストール済みパッケージ内の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 |
| Detox | .detoxrc*、package.json 内の detox | migrate/detox | mobile |
| Maestro | appId: と --- で始まる YAML フロー、.maestro/、スクリプトまたはワークフロー内の maestro test | migrate/maestro | mobile |
WebdriverIO と Appium にはガイドがありません。WebDriver の呼び出しは Selenium ガイドに従って対応付けてください。Appium のデバイスコマンドは、モバイルエンジンで Detox および Maestro のガイドに従って対応付けてください。この対応付けが部分的であることをユーザーに伝えてください。移行元ランナーが2つあるプロジェクトでは、進捗ファイルにセクションを1つずつ設け、ランナーを1つずつ移行します。
1. 再開または開始する
e2e 設定ファイルの隣、次にリポジトリのルートで MIGRATION.md を探してください。ファイルがある場合は、2回目以降のセッションです。
- ファイルを読み、続いて
Source行に記載された移行ガイドとエンジンページを読んでください。Nextセクションに、このセッションで取り組む部分が記載されています。ただし、ユーザーが別の対象を指定した場合はそちらを優先します。 - 内容をそのまま信用せず、リポジトリと照合してください。
portedと記載されたテストが両方のスイートに残っていること、記載された移行元ファイルまたはテストがすべて存在すること(意図的に削除されたretiredのものを除く)、新しい移行元ファイルまたはテストが漏れなく記載されていることを確認してください。記載漏れがあればtodoとして追加します。Defect check:の行がない場合は、手順2に従って確認してください。Nextに埋め込まれた不具合が記載されている場合は、まず元に戻してください(手順6)。 - ファイルの
Run newコマンドを1回実行してください。移植済みテストが失敗した場合は、新しい部分に着手する前に、まずその失敗を修正してください。 - 進捗ファイルの
Harness:行にdoneと記載されていない場合は、手順3の「ハーネスを構築する」に進んでください。そうでなければ、手順4の「対象を選ぶ」に進んでください。
進捗ファイルがない場合は、最初のセッションです。手順2と3を実行してから、残りの手順に進んでください。
2. スイートの棚卸し(最初のセッション)
リポジトリから以下の項目を確認してください。確認できないことだけ、ユーザーに尋ねてください。
| 質問 | 確認する場所 | 決定する内容 |
|---|---|---|
| ソースランナー | 上記の検出表 | この表の前に読む2つのドキュメント |
| テスト | すべての spec、flow、test ファイルと、そのタイトル、タグ、プラットフォーム別またはブラウザー別の分岐。grep ではループ内で定義されたテストが見落とされるため、テスト数はランナー独自の list または dry-run モードで数えます。npx playwright test --list は、テストが実行されるプロジェクトごとに1回ずつ表示するため、複数のプロジェクトで実行されるテストは1回として数えます | 進捗ファイルの行(ソースファイルごとに1行)。ポート後に件数を照合できるよう、各ファイルのアサーション数も今のうちに数えます。明示的なもの(expect、should、assertVisible)に加え、ランナーのステップがチェックとなる場合(Maestro の tapOn は対象が見つからないと失敗します)は、それらのステップも数えます |
| 共有コード | ページオブジェクト、カスタムコマンド、サブフロー(runFlow: file.yaml)、フィクスチャ、フック、globalSetup | 最初に必要となるテストの前に、一度だけポートするヘルパー |
| 実行方法 | スイートを実行する CI ジョブと、そのジョブが呼び出すスクリプト(ビルド、起動するサービスとモックサーバー、シードとリセットの呼び出し、env ファイル、デバイスまたはブラウザー、ポート) | e2e ハーネス。通常、CI ジョブが唯一の完全な説明です。1行ずつ確認してください |
| e2e の配置場所 | package.json がある JavaScript または TypeScript プロジェクトの場合:そのルート(モノレポでは、ソースランナーの設定ファイルと同じ階層)に、tests/**/*.e2e.ts のテストを配置します。ネイティブ、Java、または Python のプロジェクトの場合:アプリの隣に、独自の package.json を含む e2e/ フォルダーを配置します。そのうえで、ソースランナーのファイルパターン(testDir、testMatch、specPattern、flow フォルダー)を確認します | e2e 設定と進捗ファイルの配置場所。2つのランナーが互いのファイルを収集しないようにします。パターンが重複する場合は、どちらかを絞り込みます。Playwright のスイートでは、ファイル名にすでに *.e2e.ts を使っていることが多く、その場合はディレクトリだけが分離手段となります。Playwright の testDir 配下に e2e テストを置かず、e2e の tests glob 配下に Playwright のファイルを置かないでください。npx playwright test --list と npx e2e list を比較します |
| この環境で旧スイートを実行できるか | インストール済みのソースランナー、その実行に必要なビルド、サービス | パリティを旧スイートの実行結果(ステップ6)と照合するか、ソーステキストとのみ照合するか |
今すぐ MIGRATION.md を作成します(形式はステップ8を参照)。すべてのソースファイルのステータスは todo にします。
各スライスも意図的に埋め込んだ不具合に対して実行するかどうかを尋ね(ステップ6)、回答を Defect check: on または off として記録します。
3. ハーネスを構築する(一度だけ)
ハーネスとは、設定、アプリの起動、そして成功するテスト1件のことです。一度構築して進捗ファイルにその旨を記録したら、以降のセッションではこの手順を省略します。
- e2e の設定がない場合は、
npx e2e init --yes(トピックsetup)を実行します。デバイスプロジェクトでは--engine mobileを指定します。サンプルテストは削除するか、書き換えてください。ソースのテストスイートが対象とするプラットフォームまたはブラウザーごとに、ターゲットを1つ設定します。 - テストの手順でどのモデルエージェントを使うかユーザーに尋ね、設定します(トピック
agent)。文字どおり移植する場合は不要です。すべてのテストを決定的に実行でき、モデルを設定しない場合はそのように実行されます。 - CI ジョブが行うオーケストレーションを移植します。新しいスクリプトは作成せず、リポジトリ独自のスクリプトを再利用してください。
- アプリを提供する単一のプロセス(開発サーバー、Expo 開発クライアント用の Metro など)を、
readyUrlを指定したターゲットのapp.commandに設定します(トピックsetup)。コマンドに渡されるのはPATH、HOME、一時ディレクトリの環境変数、およびcommand.envだけで、シェルの環境変数は渡されません。そのため、以前のランナーの環境変数からサーバーが読み込んでいた値をcommand.envに渡してください。 - e2e に
servicesキーはありません。データベース、キュー、モックサーバーは、CI ジョブで使うコマンドで実行前に起動するか、app.commandでそれらを起動してからアプリを提供するスクリプトを実行します。コマンドを進捗ファイルに記録してください。 - ソースでテストごとに実行していたリセットまたはシード処理(
http.postを使うrunScript、cy.task('db:reset')、beforeEach内の API 呼び出し)は、beforeEach内の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)を使って子プロセスで実行し、フィクスチャから呼び出してください。読み込めるようにアプリのモジュールを編集しないでください。 - 環境変数の値はモジュール定数にし、パスワードとトークンは
credentialsまたはsecretsに設定します(トピックsetup)。以前の設定で環境変数ファイル(dotenv.config())を読み込んでいた場合は、e2e の設定でも同じ方法で読み込み、テストとヘルパーが同じ値を参照できるようにします。app.commandからはこれらの値を参照できないため、サーバーが必要とする値はcommand.envに渡してください。
- アプリを提供する単一のプロセス(開発サーバー、Expo 開発クライアント用の Metro など)を、
- 最も簡単なソーステストを、スモークテストとして移植します。サインインやアプリの起動テストがよく使われます。他のテストを移植する前に、すべてのターゲットで成功しなければなりません。成功しない場合、問題があるのはテストではなくハーネスです。ハーネスを修正してください。
initは、同名のスクリプトがすでに存在しない場合、test:e2eスクリプト(e2e run)を追加します。その名前がすでに使われている場合、またはinitを実行していない場合は、空いている名前でスクリプトを追加してください。古いスイートのスクリプトはそのまま維持します。- 依存関係の起動、古いスイートの実行、新しいスイートの実行に使うコマンドを記載して、進捗ファイルでハーネスの構築完了を示します。
4. 移植する範囲を選ぶ
スライスとは、このセッション中に成功させて完了できる範囲のことです。通常は1〜5件のテストを含む、1ファイル、1フォルダー、1タグ、または1つの機能領域です。ユーザーにどれを選ぶか尋ねてください。ユーザーが選択を任せる場合は、次の順に提案します。
- 共有ヘルパーがすでに移植されているテスト。
- 古いランナーで頻繁に失敗するテスト。リトライが必要なもの、CI で過去に不安定だったもの、ランナーの回避策を説明するコメントがあるものなどです。こうしたテストは移植による効果が最も大きくなります。
- ガイドで
missingまたは「No equivalent」と記載されている機能が必要なテスト。優先度は最後です。
作業を始める前に、進捗ファイルの Next セクションにスライスを記録してください。これにより、セッションが中断されても作業の履歴が残ります。
5. スライスを移植する
まず、スライスの共有ヘルパーを一度だけ通常の .ts ファイルとして移植します(ランナーが収集しないよう、.e2e.ts にはしません)。たとえば、tests/support/ の下に配置します。サブフローは関数または test.extend フィクスチャになり、ページオブジェクトはフィクスチャになります(トピック writing-tests)。それぞれを進捗ファイルに記録します。
次に、各テストを一度に一つずつ移植します。
- タイトルはそのままにし、ファイルの先頭にソースを示すコメントを記載します(
// Ported from __e2e__/flows/login.yml)。これにより、レポートやレビュー担当者が対応関係を確認できます。 - まずガイドの表に沿って逐語的に移植し、ソースの各ステップにつき、await する呼び出しを一つずつ記述します。ソースの各アサーションは、それぞれ独立した e2e アサーションに対応させます。タイムアウト時に失敗する待機(
waitForFunction)も一つとして数えるため、e2e の数はインベントリの数以上になります。 - ソースでスキップされているテストも完全に移植し、ソースと同じ理由でスキップ状態にしておきます。そうすれば、どちらのスイートでも再び有効にできます。その行にもその旨を記載し、理由が許す場合はスキップを解除して一度実行し、結果を記録します。
- ロケーターを書く前に、正確な名前を確認します。トピック
mcpに従い、open_session、observe、locateを使ってe2e mcpを実行します。クライアントにe2eMCP ツールがない場合は、テストを実行し、トピックdebuggingに従ってトレースページに記載された画面を確認します。ブリッジは作成しないでください。セレクターに関するガイドの注記には、移植の大半で必要になる編集が記載されています。e2e は文字列全体と一致するものを対象とし、旧ランナーが最初の一致を選んでいた場合でも、複数の一致があると失敗します。クエリが別のレイアウトにある非表示のコピーにも一致する場合は、{ visible: true }を追加します。最初のトーストに重なって表示される2つ目のトーストのように、表示中のノードが2つ一致する場合は、そのステップが意図する方を選びます。 - スリープまたは固定時間の待機は、待機していた状態に対する
agent.waitFor(agent.waitFor('the upload finished'))に置き換えます。または、ロケーターでその状態を指定できる場合、あるいは設定にモデルがない場合は、timeoutを指定したアサーションに置き換えます。待機時間は移植しないでください。 - プラットフォームごとの分岐は、テストに
{ platforms: [...] }を指定するか、テスト内でplatformフィクスチャに対するifを使います。 - ソースのコメントで説明されている回避策(不安定な
hideKeyboard、座標指定のタップ、ピッカー周りのリトライループ)は、旧ランナー用の回避策です。まず通常のステップを試し、e2e でも必要な場合に限り、理由を説明する専用のコメントを付けて回避策を残します。 - ガイドでステップが
missingまたは「No equivalent」とされている場合は、ガイドの回避策を使います。回避策がない場合、そのテストは旧ランナーに残します。理由とともにstaysと記載し、npx e2e feedback --type feature -m "<the gap>"を一度送ることを提案します。--dry-runでプレビューし、ユーザーが同意した場合に限り送信します(e2e スキルの Feedback を参照)。 - アプリのコードは変更しないでください。アプリにテスト ID がないためにテストが必要とする場合は、
agent.actまたは別のロケーターを使います。アプリの変更は自分で行わず、ユーザーに提案してください。例外は不具合確認用に仕込まれたバグ(ステップ6)で、同じセッション内で元に戻します。
逐語的な移植が通った後に限り、agent.act を使えます。モデルが設定されている場合のみ使用してください。ソースでパッチを重ねていたような手間のかかる操作(座標指定のタップ、ピッカーの操作、ウィザードでの長いタップ操作列)には、使用を提案します。その直後にロケーターのアサーションで結果を確定します(トピック agent)。
6. 各ポートを検証する
ポートが完了したと言えるのは、ソースと同じ厳密さを保ち、毎回パスするときです。
- ソースで対象としていたすべてのターゲットで実行します。
npx e2e run <file> --repeat-each 3を実行し、エージェントの ステップがある場合は--no-cacheも付けます。各ターゲットで3回中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 テストスイートを追加することを提案します。古いランナーのワークフローを編集するため、変更はユーザーの同意を得てから行います。ビルド、サービス、デバイスは既存のものを再利用します。2つのランナーが同時に1台のデバイスまたはシミュレーターを操作することがないようにします。同じジョブ内で順番に実行するか、それぞれに専用のデバイスを割り当てます。e2e ジョブではポート済みのテストをすべて実行するため、後の変更でテストが1つでも壊れると、プルリクエストが失敗します(トピック
running、継続的インテグレーション)。 - 最後のソーステストが
retiredまたはstaysと記されたら、進捗ファイルに移行が完了したことと、残すテストがあればその内容を記します。
8. 進捗ファイルを保つ
e2e の設定と同じ場所にある MIGRATION.md が、移行の状態を示します。最後にまとめてではなく、作業に合わせて更新してください。セッションが中断されても、内容が正しい状態を保てるようにします。
# Migration to e2e
Source: Maestro, `__e2e__/flows/**` (guide: https://e2e.tester.army/docs/migrate/maestro.md, engine: https://e2e.tester.army/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: missing); feedback sent.
## Next
flows/composer.yml and flows/composer-self-label.yml (both need `signInAlice()`).
ソースファイルごとに1行記載します。テストのステータスが異なるファイルは、テストごとに1行ずつ記載し、それぞれのアサーション数を記録します。何百ものテストがあるテストスイートでもファイル単位の行を使います。テーブルは 毎回のセッション開始時に確認します。
ステータス:todo、ported(e2e でパスし、ソースのテストも引き続き実行される)、retired(ユーザーの確認を得て、ソースのテストが削除された)、blocked(試したが、まだパスせず、失敗した内容を記載)、stays(理由を添えて、意図的に古いランナーに残す)。
9. 引き継ぐ
このセッションで進めた内容と、確認できたことをユーザーに伝えます。ポートしたテストとターゲットごとのパス数、不具合チェックの結果、ポートしたヘルパー、ブロック中または残すものとその理由、報告した問題、次に取り組む範囲を伝えます。
どの ported 状態のソーステストを廃止してよいか尋ねます。作成または変更したファイルをすべて列挙します。
ルール
- 1 セッションにつき 1 スライスにします。両方のテストスイートをグリーンに保ちます。以前と同じように旧テストスイートがパスし、すべての
portedテストがパスする状態にします。 - ユーザーの確認なしに、ソーステスト、ヘルパー、旧ランナーの設定を削除または編集してはいけません。
- リポジトリに示されている内容に基づいて移植します。進捗ファイルに記載したすべてのコマンドを、少なくとも 1 回実行します。ここでは実行できないコマンド(旧ランナーがインストールされていない場合など)は、その旨を進捗ファイルに記載します。
- 無効なコントロールのタップや、座標タップが外れる可能性がある場合など、ソースの手順の意味が不明確でも、その意図を移植に残します。読み取った内容を進捗ファイルに記載し、ユーザーに確認します。
- e2e スキルまたはガイドの一文を、自分で書いた段落より優先します。トピック名またはガイドのセクション名を記載します。
- テスト、設定、進捗ファイルにシークレットを記載してはいけません。クレデンシャルの名前を記載します(トピック
setup)。 - ユーザーに代わってコミットしてはいけません。