Playwright導入で失敗した話7選|実務で躓いたポイントと対策を解説

PlaywrightでE2Eテスト自動化を導入したQAエンジニアが実際に経験した「失敗談」を7選で解説します。auto-waiting過信・言語選択ミス・CI環境差異・チーム導入の抵抗など、Playwright固有の躓きポイントと対策を実務経験をもとに紹介します。

「Playwrightに乗り換えれば解決する」——その思い込みが、次の失敗の始まりでした。ツールを変えても、使い方を間違えれば結果は同じです。

📌 この記事はこんな方におすすめ

  • PlaywrightでのE2Eテスト導入を検討しているQAエンジニア
  • SeleniumからPlaywrightへの移行を考えているエンジニア
  • Playwright導入後に「思ってたのと違う」と感じている方
  • チームへのPlaywright導入を推進しようとしているリード・マネージャー

✅ この記事を読むと得られること

  • Playwright固有の失敗パターン7つと具体的な原因がわかる
  • 「実装レベルのはまりポイント」ではなく「導入・運用レベルの判断ミス」がわかる
  • 各失敗に対する具体的な回避策・改善策がわかる

👤 この記事を書いた人

QAエンジニア・テスト自動化エンジニアとして15年以上の実務経験を持つ Yoshi が執筆。Selenium・Playwright・pytest を実務で使い、Playwright導入時に「こうすればよかった」と感じた失敗を、包み隠さず共有します。

📖 関連記事との使い分け

📌 結論(3つのポイント)

  • Playwright導入の失敗の多くは「ツールの問題」ではなく「導入計画・言語選択・チーム設計」の問題
  • auto-waiting・page.route()・CI環境はPlaywright固有の落とし穴があり、事前に知っていれば回避できる
  • Playwright自体は優れたツール。失敗を知った上で使えば、長期的に大きな価値を発揮する

「SeleniumでFlaky地獄に陥ったからPlaywrightに乗り換えよう」——2年前の自分の判断は半分正解で、半分間違いでした。

Playwright自体は確かに優れたツールです。でも「乗り換えれば万事解決」という思い込みで進めたことで、Playwright固有の新しい失敗を量産しました。この記事では、その体験談を7つにまとめて包み隠さず共有します。

Playwright導入で失敗した話7選とは?早見表

#失敗の内容根本原因
「乗り換えれば万事解決」という過信ツール選定の思想レベルのミス
auto-waitingを過信してタイムアウトまみれになったPlaywright固有機能の誤解
TypeScriptで始めてチームが誰も保守できなくなったチームスキルを無視した言語選択
page.route()でモックしたつもりが実APIを叩いていたネットワークモックの仕組みへの誤解
CI環境でブラウザが起動しない問題を放置したローカル依存の開発習慣
バージョンアップで一気に30テストが落ちた依存管理・アップデート戦略の欠如
「なぜPlaywrightか」をチームに説明できなかったツール選定の根拠が自分の中にしかなかった

① 「Playwrightに乗り換えれば万事解決」という過信とは?

何が起きたか

SeleniumでFlakyテストが増えて限界を感じたとき、「Playwrightはauto-waitingがあるからFlakyが解消する」「モダンなAPIで保守しやすい」という評判を信じて、既存の200件のSeleniumテストをすべてPlaywrightに書き直すプロジェクトを立ち上げました。結果としてFlakyは減りましたが、ゼロにはなりませんでした。そして書き直しに3ヶ月かけた工数は、テスト設計の改善には使われませんでした。

⚠️ 本当の問題:FlakyになっていたSeleniumテストの多くは、テスト設計自体に問題があったのです。外部依存が強い・仕様が安定していない・セレクタが脆弱——これらはPlaywrightに変えても解決しません。「ツールを変える」前に「テスト設計を直す」判断が先でした。
💡 対策:Playwrightへの移行前に「なぜFlakyが起きているか」を分析しましょう。原因が「Seleniumの同期処理の限界」ならPlaywrightで解決します。しかし「テスト設計の問題」なら、先に設計を直してから移行する方が長期的なコストが低くなります。

Playwrightで改善するFlakyと改善しないFlakyの違い

Flakyの原因Playwrightで改善?理由
Seleniumのimplicit wait不足✅ 改善するauto-waitingで自動的に待機
ChromeDriverバージョン不一致✅ 改善するバイナリをライブラリと一緒に管理(ただしinstall実行・CIキャッシュの設定は別途必要)
アニメーション中の操作タイミング△ 部分的に改善stableチェックはあるが完全ではない
外部APIのレスポンスが不安定❌ 改善しない外部依存はツールで解決できない
テスト間のDB・状態の競合❌ 改善しないテスト設計の問題はツールで解決できない
CI環境のCPU・メモリ性能差△ 部分的に対応可timeout値の調整で緩和できるが根本解決ではない
ネットワークの揺らぎ・遅延❌ 改善しないモック化で回避するのが正解
並列実行時のテスト間競合❌ 改善しないテスト設計(独立性の確保)で解決する

② auto-waitingを過信してタイムアウトまみれになったとは?

何が起きたか

「Playwrightはauto-waitingがあるから明示的な待機処理は不要」——この理解で書き始めたテストは、しばらくすると謎のタイムアウトエラーを量産し始めました。

⚠️ まず正確に理解する:PlaywrightのLocator APIは、クリックなどの操作時に actionability check(visible・stable・enabled・receives events など) を自動実行します。ただしこれは「その瞬間に条件を満たしているか」のチェックであり、「非同期状態変化そのものを待つ」わけではありません。APIレスポンス待ちや非同期でのenable状態への変化は、expect() を併用した明示的な待機が必要です。
# ❌ auto-waitingに頼りすぎた書き方
# locator.click()はactionability checkを行うが、
# 非同期状態変化や独自UIコンポーネントでは明示的な待機が必要になるケースがある
page.locator("#submit-btn").click()
# ↑ 非同期でdisabled→enabled に変わるボタンは、
#   変化のタイミングによってタイムアウトになることがある

# ✅ 現代的なLocator API + expect()で意図を明示する
from playwright.sync_api import expect
expect(page.locator("#submit-btn")).to_be_enabled()
page.locator("#submit-btn").click()
⚠️ actionability checkが解決しないケース:

  • 非同期でdisabled→enabled に変わるボタン:タイミングによってはdisabledのままクリックを試みてタイムアウト。expect(locator).to_be_enabled() で先に状態を確認する
  • APIレスポンス後に表示されるコンテンツ:DOMに存在しない間は待ってくれるが、APIが遅い場合は全体タイムアウトになることがある
  • アニメーション中の要素:stableチェックはあるが、CSSアニメーションの実装によっては想定どおりに動かないケースがある
  • Shadow DOMの内部要素:セレクタの書き方によってはattachedと正しく判定されない
💡 対策:auto-waitingは非常に強力ですが、「すべての非同期状態変化」を解決してくれるわけではありません。expect(locator).to_be_enabled()expect(locator).to_be_visible() を組み合わせると「何を待っているか」が明示されてFlakyが減ります。なお page.wait_for_selector() は完全非推奨ではなく、hidden/detach状態の待機など一部の用途では今でも実務利用されますが、新規コードはLocator API + expect() が公式推奨スタイルです。

③ TypeScriptで始めてチームが誰も保守できなくなったとは?

何が起きたか

「PlaywrightはTypeScript/Node.js版のサンプル・ドキュメント量が最も豊富」「型があった方が保守しやすい」という理由でTypeScriptを選択しました。自分はJavaScriptの経験があったので書けましたが、チームの他のメンバーはPythonエンジニアばかり。半年後にはテストコードのレビュアーが自分一人になり、事実上の属人化が完成していました。

判断軸TypeScriptPython
公式サンプル・ドキュメントの豊富さ✅ 最も情報量が多い✅ 十分なサポートあり
型安全性・補完✅ 強力△ 型ヒントで対応可
Pythonチームが多い現場での保守性❌ 属人化リスク高✅ 全員が触れる
pytest との統合❌ 別エコシステム✅ pytest で統合可
💡 対策:言語はチームの多数が読み書きできるものを選ぶのが鉄則です。「公式推奨」より「チームが保守できる」を優先してください。PythonチームならPlaywright + pytest(Python版)で十分な機能が揃っています。「型安全性が欲しい」なら後からPythonの型ヒントを追加する方が現実的です。

④ page.route()でモックしたつもりが実APIを叩いていたとは?

何が起きたか

page.route() でAPIをモックしたつもりが、なぜかテスト結果が実際の本番データに依存していました。調査してわかったのは、テスト対象のAPIがJavaScript(ブラウザ)経由ではなく、サーバーサイドレンダリング(SSR)で直接叩かれていたというケースです。

⚠️ まず正確に理解する:page.route()Browser Context 内のHTTP通信 のみをinterceptします。一方、PlaywrightのAPIテスト用 request fixture は APIRequestContext という独立したHTTPクライアント として動作するため、通信レイヤが完全に別です。「Playwrightだからpage.route()で全部モックできる」という誤解がハマりの根本原因です。
# page.route() はブラウザのHTTP通信のみをインターセプト
await page.route("**/api/users", lambda route: route.fulfill(
    status=200,
    body='{"users": []}'
))
# ↑ SSRやNext.jsのgetServerSideProps内でのfetchは傍受できない
# ↑ Playwright API Testing(request fixture)のHTTP通信も傍受できない
⚠️ page.route()がinterceptできない主なケース:

  • SSR/SSG:Next.js・Nuxtなどのサーバーサイドでのfetch(Node.js側の通信のため)。この場合はupstream APIのモックやNode側でのモック対応が必要
  • Service Worker:PWAやMSW(Mock Service Worker)導入環境でSWが通信を横取りしているケース。fetchがSW経由になっているとpage.route()が届かない
  • WebSocket:WebSocket通信は別途 page.on("websocket") で対応
  • Playwright API Testing(request fixture):Node.js側のHTTPクライアント通信
💡 対策:「モックが効いているか」を必ずテスト内で検証しましょう。route.fulfill() のレスポンスが実際に返ってきているかをネットワークタブで確認します。SSR環境やService Worker環境では、msw・Nock・WireMock などのサーバー側またはSW側のモックと組み合わせるアプローチが有効です。「page.route()で全部モックできる」という前提で設計すると、環境によってハマります。

⑤ CI環境でブラウザが起動しない問題を放置したとは?

何が起きたか

ローカルでは完璧に動くのに、GitHub Actionsに乗せると「ブラウザが起動しない」「依存ライブラリが足りない」エラーが続出しました。原因はわかっているのに後回しにして、「ローカルで動かして手動でCIに結果を報告する」という本末転倒な運用を2週間続けてしまいました。

CI環境でよく発生するPlaywright起動エラー

エラーの種類原因対策
BrowserType.launch: Executable doesn't existブラウザバイナリが未インストールnpx playwright install --with-deps
error while loading shared librariesLinux依存ライブラリ不足--with-deps オプションで解決
タイムアウトがローカルより頻発CIマシンのCPU・メモリがローカルより低いtimeout を2〜3倍に設定
ヘッドレスモードで挙動が違うviewport差・GPU非対応・hover非動作・animation timing差異・Intersection Observer挙動差など--headed で挙動確認・テスト設計を見直す
💡 対策:Playwright導入の最初の1日目にCI環境で動かすことを強くおすすめします。「ローカルで動いたらCI対応は後で」という判断が最大の時間泥棒になります。GitHub Actionsへの組み込みはPlaywrightの公式ドキュメントに最小構成のYAMLが掲載されているので、それをそのまま使うのが最速です。

⑥ バージョンアップで一気に30テストが落ちたとは?

何が起きたか

pip install playwright --upgrade でバージョンを上げたら、翌日のCIで30件のテストが一気に落ちました。原因はバージョン間でのAPIの変更と、ブラウザバイナリのバージョン不一致です。

# ❌ バージョン固定なし(アップデートのたびに壊れるリスク)
playwright

# ✅ バージョンを固定(requirements.txt)
playwright==1.44.0

# ブラウザバイナリも必ず再インストール
# pip install playwright==1.44.0 の後に必ず実行
# playwright install chromium
⚠️ Playwright特有のバージョン管理の注意点:Playwrightはライブラリバージョンとブラウザバイナリのバージョンが1対1で対応しています。ライブラリだけアップグレードしてブラウザバイナリを更新しないと、「APIは新しいのにブラウザが古い」という不整合が起きてテストが壊れます。
💡 対策:バージョンアップは「専用のアップデートブランチを切る → ローカルで全テスト実行 → CIで確認 → 問題なければmain」という手順を踏みましょう。また requirements.txt のバージョン固定は必須です。Renovate・Dependabot でバージョンアップのPRを自動作成する仕組みを入れると、アップデートの管理が楽になります。

⑦ 「なぜPlaywrightか」をチームに説明できなかったとは?

何が起きたか

「Playwrightの方がいいから」と自分一人で決めてチームに展開しようとしたとき、先輩エンジニアから「なぜSeleniumじゃダメなの?」と聞かれ、うまく答えられませんでした。「なんとなくモダンだから」「Twitterで評判がいいから」——これでは技術的な意思決定として弱すぎます。結果として「とりあえず今のSeleniumで続けよう」となり、移行プロジェクトが半年間宙に浮きました。

チームを説得できる「なぜPlaywrightか」の根拠

比較軸SeleniumPlaywright
auto-waiting手動でtime.sleep/waitが必要要素がDOM+visibleになるまで自動待機
ChromeDriver管理Chromeバージョンと手動で合わせる必要ブラウザバイナリを自動管理
APIテストとの統合別ライブラリ(requests等)が必要request fixtureでE2E+APIを統合
ネットワークモック別途モックサーバーが必要page.route()でブラウザ通信をモック
HTML Report / Trace別途Allure等のセットアップが必要組み込みHTMLレポート・Trace Viewer
💡 対策:ツール移行を提案するときは「現状の課題リスト → Playwrightでどう解決するか → 移行コストの試算」の3点セットで資料を作りましょう。特に「ChromeDriver管理の手間」「FlakyテストのログがHTMLレポートで追いやすい」は、チームメンバーが日常的に困っているポイントなので、刺さりやすい説明です。

FAQ

Q. SeleniumからPlaywrightに移行する価値はありますか?

あります。ただし「移行さえすれば解決する」という過信は禁物です。ChromeDriver管理の撤廃・auto-waiting・HTMLレポートの組み込みなど、運用コストを下げる要素が多いのは事実です。「今のSeleniumで何が困っているか」を整理してから判断すると、移行の効果を最大化できます。

Q. Playwright導入はどこから始めるのが正解ですか?

「新規テストを1〜2件だけPlaywrightで書いて、CIに乗せるところまでやりきる」のが最初のステップとしてベストです。既存テストの全移行から始めると工数と学習コストで詰まります。小さく動かして成功体験を作ってから、徐々に範囲を広げていくのが失敗しにくいアプローチです。

Q. Python版とTypeScript版、どちらを選ぶべきですか?

チームの主要言語に合わせるのが最善です。PythonエンジニアのチームならPython版(playwright-pytest)が保守しやすく、既存のpytestスタックとも統合できます。TypeScriptは機能的に最もサポートが手厚いですが、「誰も保守できない」テストコードは最悪の状態です。チーム全員が読み書きできる言語を選んでください。

Q. auto-waitingがあるのになぜFlakyテストが発生するのですか?

auto-waitingは「要素がDOMに存在してvisibleになるまで」待つ機能です。「操作可能(enabled)になるまで」「APIレスポンスが返るまで」「アニメーションが完了するまで」は別途明示的な待機処理が必要です。Flakyが多い場合は、auto-waitingの対象外のケースが混入していないか確認してください。

Q. Playwrightのバージョンはどう管理すればいいですか?

requirements.txt でバージョンを固定し、アップデートは専用ブランチで全テストの通過を確認してからmainにマージするのが基本です。Playwrightはライブラリとブラウザバイナリのバージョンが連動しているため、ライブラリをアップデートしたら必ず playwright install でブラウザも更新してください。

Playwright自体は本当に優れたツールです。この記事で紹介した失敗は、すべて「Playwrightの問題」ではなく「使い方・導入計画・チーム設計」の問題でした。失敗のパターンを知った上で始めれば、同じ轍を踏まずに済みます。小さく始めて、CIに乗せて、チームで使える状態を作る——この順番で進めることが、Playwright導入を成功させる最短ルートです。

📋 この記事のまとめ

  • 「Playwrightに移行すれば解決する」は半分正解。テスト設計の問題はツールを変えても解決しない
  • auto-waitingは「visible」まで待つ機能。「enabled」「APIレスポンス待ち」は明示的な待機が別途必要
  • 言語選択はチームの多数が保守できるものを優先。「公式推奨」より「チームが使える」が重要
  • page.route()はブラウザの通信のみモック。SSR・WebSocket・request fixtureには効かない
  • CI対応は導入初日にやりきる。「後で」が最大の時間泥棒になる
  • バージョンアップはライブラリとブラウザバイナリをセットで管理。固定バージョンで運用する
  • チームへの導入は「現状課題→解決策→移行コスト試算」の3点セットで説得力を持たせる
タイトルとURLをコピーしました