freeeの開発情報ポータルサイト

1年かけてE2Eの実装基盤と実行基盤をリプレイスした話

こんにちは。SEQ (Software Engineering in Quality)のtatsukomです。私たちのチームは、現在自動テストの基盤開発、さらには開発フィードバックサイクルの高速化を目指した開発を進めています。

freee QA Advent Calendar2025 4日目です。

これまで、freeeのE2Eテスト(ブラウザテスト)の実装基盤は、Selenium+RSpec+Capybara+SitePrismをベースにした独自基盤(以下、まとめてSeleniumと表記します)を開発・運用してきました。この基盤で実装されたE2Eテストの実行基盤にはJenkinsを利用していました。しかし、これらの基盤には多くの課題があり、実装基盤と実行基盤をリプレイスすることにしました。実装基盤はPlaywrightをベースにした新しいE2Eテスト基盤を開発し、実行基盤はGitHub Actionsを利用する形にしました。 この記事では、なぜ実装基盤と実行基盤をリプレイスしたのか、そしてどのように移行を進めたのかについて紹介します。

これまでの構成

これまでのE2E基盤の全体像

これまでのE2Eテストの基盤の全体像は以下の通りです。実装基盤で作成されたE2Eテストは下記図のような形で実行されていました。

これまでのE2E基盤の全体像
これまでのE2E基盤の全体像

E2Eテストを実行するフローは以下の通りです。

  1. 事前にSeleniumのリポジトリをJenkins上にCloneしておく
  2. E2Eテストの実行用コマンドをSlackに投稿する
  3. Slack appからJenkinsのJobを実行する
  4. Jenkinsが検証環境に対してE2Eテストを実行する
  5. ログとE2Eテストが落ちた際の画面のスクリーンショットをEC2上のストレージに保存する
  6. 実行結果をSlack通知する
  7. 落ちたE2EテストのログとスクリーンショットをJenkins上で確認する

次に実装基盤と実行基盤のそれぞれの課題について紹介します。

実装基盤が抱えていた課題

Seleniumはプロダクト横断で利用するモノレポになっています。社内のエンジニアはE2Eのレイヤーで確認したいテストケースのこのモノレポにE2Eテストを実装していました。 実装基盤には大きく分けて以下の3点が課題になっていました。

  • 要素取得が大変
  • マルチブラウザで動かない
  • テストの事前準備をすべてブラウザ操作で行っているため実行に時間がかかる

要素取得が大変

あるテストで下記図の「山田 太郎」という文字列を取得したいとします。

IframeとShadow DOM
IframeとShadow DOM

この画面にはIframeとShadow DOMが存在しています(赤がShadow DOM, 青がIframe) IframeはSwitchでIframeを切り替える必要があり、Shadow DOMはShadow Rootで一度全体要素を取得する必要があります。 そのため、下記図の「山田 太郎」を取得するには以下の手順を踏む必要があります。

  1. 申請・承認付近のshadow rootの要素を取得する
  2. Shadow DOM内にあるIframeをswitchで切り替える
  3. 申請経路付近のshadow rootの要素を取得する
  4. 「山田 太郎」の文字列を取得する

これは要素取得で利用しているCapybaraの制約によるもので、解決するには利用するツールを変更する必要がありました。

マルチブラウザで動かない

Seleniumが対応しているブラウザはChromeのみであり、SafariやFirefoxでは動作しませんでした。そのため、別ブラウザでの動作確認が必要な場合は、自動テストではなく手動でのブラウザ操作による検証が必要でした。 過去にSeleniumでSafariを利用できないか調査したことがあります。CapybaraでWebKitを動かす際は、以下のGemを利用するのが一般的でしたが、このリポジトリは2020年にアーカイブ化されており、利用することができませんでした。

GitHub - thoughtbot/capybara-webkit: A Capybara driver for headless WebKit to test JavaScript web apps

WebKitではなくSafariでも検証を試みましたが、想定通りの箇所に値が入力されないなどの問題があり、Seleniumのままでは安定したSafari対応は困難と判断しました。

テストの事前準備をすべてブラウザ操作で行っているため実行に時間がかかる

Seleniumで実行するテストは、依存関係をなくすために実行のたびに毎回サインアップから始まるようになっています。そのため、サービスにはシナリオ実行に必要なデータが何も登録されていない状態であり、事前準備としてデータ登録から始める必要があります。データの登録もすべてブラウザ操作で行っている関係で、テストの実行時間が長くなるというデメリットがありました。特に事前準備が多いシナリオの場合は、実行に7分もかかるケースがありました。

実行基盤が抱えていた課題

これまでのE2E実行基盤はEC2上にJenkinsを構築し、その中でE2Eテストを実行していました。これには以下の課題を抱えていました

  • Seleniumで新規にシナリオを作成したら、そのシナリオを動かす専用のJobをJenkinsに作成する必要がある
    • Jenkins JobはIaC化されておらず、手動管理のため対応漏れ等で作成したシナリオがJenkinsで実行されていないことがあった
  • テストが落ちた時のスクリーンショットが直近の実行結果しか残らない
    • Jenkinsから確認できるスクリーンショットは直近の結果のみで、3つ前の結果を確認したい場合はデータが残っておらず確認することができない
    • そのためデータをSlackなど別の媒体に手動で保存する必要があった

その他Jenkinsの課題点は 高速でスケーラブルなE2E実行基盤を目指して - freee Developers Hub をご覧ください。

新しい構成

実装基盤

Seleniumの後継基盤としてPlaywrightを採用しました。 Seleniumで抱えていた課題は以下のように解決をしました。

  • 要素取得が大変: VSCodeのPlaywrightの拡張機能にあるPick Locatorを利用して解決。欲しい要素の途中にIframeとShadow DOMが入っていてもブラウザ操作でカーソルを合わせると要素を取得することができる
  • マルチブラウザで動かない: Playwrightの標準機能でChromium・Webkit・Firefoxで動かせる

「テストの事前準備をすべてブラウザ操作で登録している実行に時間がかかる」点については、E2Eで確認するテストシナリオを「準備・実行・検証」の3つの段階に分けるようにしました。

準備フェーズはシナリオで確認したい観点とは異なるため、ブラウザからデータを登録する必要はありません。そのため、Playwrightへの実装基盤移行の過程で、テストデータの準備方法をブラウザ経由での登録からバックエンドのAPIを直接叩く形に変更しました。実行と検証はシナリオで確認したい点であるため、これまで通りブラウザ操作で確認する方針としました。

準備をブラウザ操作からバックエンドのAPIを直接叩く形に変更した結果、先ほど紹介したテスト実行に7分かかっていたケースは、Playwrightへの移行により実行時間が1分30秒へと大幅に短縮できました。

実行基盤

Jenkinsの後継基盤としてGitHub Actionsを採用しました。

E2Eテストを作成するたびに専用のJobを作る必要があるという課題は、テスト実行専用の共通ワークフローを用意することで解決しました。リグレッションテストでテストケースをまとめて実行したい場合は、ディレクトリパスを指定することで、そのディレクトリ配下のテストをすべて実行する方針としました。詳細は 高速でスケーラブルなE2E実行基盤を目指して - freee Developers Hub をご覧ください。

テストが失敗した時のスクリーンショットが直近の実行結果しか残らないという課題は、ReportPortalという分析基盤を用意し、テスト結果をすべてここに保存することで解決しました。ReportPortalでは、テストの実行ログ、スクリーンショット、ブラウザ操作の動画を確認することができます。ReportPortalに関する詳細は E2Eテスト分析基盤としてReportPortalを導入しました - freee Developers Hub をご覧ください。

新しいE2E基盤の全体像

新しい実装基盤で作成されたE2Eテストは、下記図のような形で実行されます。

新しいE2E基盤の全体像
新しいE2E基盤の全体像

E2Eテストを実行するフローは以下の通りです。

  1. E2Eテストの実行用コマンドをSlackに投稿する
  2. Slack appからGitHub ActionsのWorkflowを実行する
  3. GitHub Actionsが検証環境に対してE2Eテストを実行する
  4. ログ・スクリーンショット等をReportPortalに送信する
  5. 実行結果をSlack通知する
  6. 落ちたE2Eテストの内容をReportPortal上で確認する

GitHub Actionsに移行したことで、テスト実行前にSeleniumのソースコードを事前にcloneする手間と、専用のJobを作成する手間がなくなりました。

どのように移行していったか

スモールスタート

Seleniumは全社的に利用されているE2E基盤であり、2016年に導入されて以降、その規模は膨大になっていました。全プロダクトのテストファイルが合計で850個もあり、事前検証なしにPlaywrightへ移行することは現場からの反発を招くと判断しました。そのため、特定のプロダクトに対してPlaywrightとGitHub Actionsの基盤を導入し、効果測定を行ってから全体の方針を決めることにしました。 実装基盤における「要素取得が困難」と「テストの事前準備をすべてブラウザ操作で行っているため実行に時間がかかる」という2点に強い課題感を持っているプロダクトに対して、協力を要請したところ、快く応じてもらえました。

まず、プロダクトチームには、Seleniumで実装していたシナリオを「準備・実行・検証」の3つのステップに分けて、テストケースを再定義してもらうよう依頼しました。再定義されたテストケースを、我々SEQチームが先ほど述べた実装方針に合わせて実装しました。具体的には、準備はバックエンドのAPIを直接叩く形、実行と検証はブラウザ操作で行う形としました。

実行基盤のGitHub Actionsと結果確認に利用するReportPortalの構築もこちらで準備し、プロダクト側に利用してもらいました。 結果は先ほども述べた通り、実行時間が7分から1分30秒へと大幅に短縮されました。また、GitHub Actionsでの実行により、JenkinsのようなJobの追加やリポジトリの配布が不要になったという喜びの声をいただきました。

新しいE2E基盤を利用された際の喜びの声
新しいE2E基盤を利用された際の喜びの声

方針決めと全社共有

この結果を受けてSeleniumとJenkinsを廃止して、PlaywrightとGitHub Actionsに完全移行する意思決定をしました。 弊社にはdev朝会という、全社向けに開発に関することを発表する場があります。ここで新しいE2E基盤に関する紹介と今後の方針について共有しました。 これまでSeleniumとJenkinsで抱えていた課題を説明し、新基盤への移行によってこれらの課題を解決できることを説明しました。 すると、Slackのワイワイスレッドは「爆速」等のコメントで非常に盛り上がり、投稿数は約110件と2024年で最多となりました。

実行時間が短くなり喜ぶみなさんの声 -> 社内のSlackで、「はやい」「爆速」といったリアクションがある様子
実行時間が短くなり喜ぶみなさんの声

Jenkinsも廃止する旨を伝えたところ、「さよならおじさん」などJenkinsとの別れを惜しむ声もありました。

Jenkins廃止に対する反応 > 「さよならおじさん」などJenkinsと別れを惜しむ声がある様子
Jenkins廃止に対する反応

移行の進捗確認

方針発表後、これまでSeleniumを利用していたプロダクトに対して、直接移行の段取りを決めるMTGを設定しました。Seleniumを利用しているプロダクトは約20個ありましたが、すべてのプロダクトと直接移行の段取りを決めました。 プロダクト側にはE2Eテストで確認するリグレッションテストの項目の整理をはじめにお願いし、そこから現在Seleniumで実装されているテストの移行有無を判断してもらいました。その中から数個のテストを我々SEQチームではじめに実装し、その後に残りをプロダクトチーム側で実装してもらう流れにしました。 プロダクトチームに実装を依頼してからは、SEQチームで週次で移行の進捗を確認するようにしていました。移行が順調に進んでいないチームに対しては、個別に声をかけて必要なフォローを行いました。

Seleniumの残りファイル数の推移グラフ
Seleniumの残りファイル数の推移グラフ

プロダクト側の積極的な協力と、Claude Codeなどのコーディングエージェントの登場により、2024年11月に移行を開始してから2025年10月に移行を完了することができました。

最後に

freeeで利用されているE2Eの実装基盤と実行基盤をリプレイスした話を紹介しました。よかったら参考にしてみてください。

明日は、sunny-sanが「baas QAの日常 ~上流工程からのテスト観点洗い出し紹介~」の記事を書いてくれます。

それでは、よい品質を〜