Playwrightで「テスト自動化」を資産に変える:深夜の呼び出しをゼロにする戦略的実装
「またかよ」。深夜2時、枕元で鳴り響くSlackの通知音。本番デプロイ直後に飛んでくるアラート。原因は、ローカルでは完璧に動いていたはずのE2Eテストが、CI環境でだけ気まぐれに落ちる「Flakyテスト」だ。
E2Eテストは、やり方を間違えれば開発者の足を引っ張る「負債」になる。だが、Playwrightの設計思想を正しく理解すれば、それは最強の「守護神」に変わる。今日は、設定地獄から抜け出し、現場で叩き上げた「鉄壁のテスト環境」を構築するロードマップを共有する。
1. なぜ「設定地獄」に陥るのか
多くのプロジェクトで見る `playwright.config.ts` は、肥大化しすぎている。数千行の設定を読み解くのは、もはやデバッグではなく考古学だ。
反面教師:設定を詰め込みすぎた例
// こういう「なんでも入り」の設定は、依存関係が複雑になりすぎて誰も触れなくなる
export default defineConfig({
timeout: 60000,
expect: { timeout: 10000 },
use: {
actionTimeout: 5000,
navigationTimeout: 5000,
// ...無限に続くオプション
},
// 結局、何が原因で落ちたのか追跡不能になる
});
結論から言うと、設定はデフォルトに近いほど強い。 Playwrightの標準機能(Auto-waiting)は、下手に設定を弄るよりも遥かに賢い。設定をいじるのは、デフォルト値ではどうしても解決できない「特殊な要件」が出てきた時だけで十分だ。
2. Flakyテストを撲滅する「アサートの哲学」
「要素が見えたらOK」という書き方は、今すぐやめろ。それがFlakyテストの温床だ。
// ❌ 危険:アニメーション完了を待たずに判定される可能性がある
await expect(page.locator('.modal')).toBeVisible();
// ⭕ 推奨:データが反映されるまで待つ
await expect(page.locator('.user-name')).toHaveText('Taro Yamada');
なぜ `toHaveText` が強いのか? Playwrightは内部的に `MutationObserver` を使い、DOMの変更を監視している。`toBeVisible` は単なる「表示状態」の確認だが、`toHaveText` は「期待するデータがDOMに注入されるまで」を待機する。これこそが、非同期処理の多いモダンなSPAにおいて、テストを安定させる唯一の解だ。
3. CIの爆速化:シャardingの魔力
テストが増えるたびにCIが遅くなるのは、並列化の怠慢だ。GitHub Actionsの `sharding` を使えば、テストを物理的に分割できる。
# .github/workflows/e2e.yml
jobs:
playwright:
runs-on: ubuntu-latest
strategy:
matrix:
shard: [1, 2, 3, 4]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm' # node_modulesのキャッシュはここで十分
- name: Install dependencies
run: npm ci && npx playwright install --with-deps
- name: Run Tests
run: npx playwright test --shard=${{ matrix.shard }}/4
注意:並列化の落とし穴
シャardingを導入する際、「テスト間の依存関係」には細心の注意が必要だ。- IDの重複: 同じユーザーデータでテストを走らせると、DB競合で必ず落ちる。
- 解決策: テストごとにユニークな名前のユーザーを生成するか、テスト終了後にクリーンアップする設計を徹底すること。
4. キャッシュ戦略の「嘘」を見抜く
巷では「`playwright-browsers` をキャッシュしろ」という声が多いが、これには注意が必要だ。キャッシュの復元に時間がかかりすぎて、結局 `npx playwright install` を実行するのと大差ない時間がかかるケースが多々ある。
- `node_modules`: `setup-node` のキャッシュ機能で十分。
- `playwright-browsers`: CIのネットワークが安定しているなら、無理にキャッシュせず毎回クリーンインストールする方が、環境起因の「謎のバグ」を排除できる。
5. 最後に:テストは「コードベースの鏡」
テストコードが読みづらい、あるいはメンテナンスが困難なら、それはプロダクトコードの設計が悪いというサインだ。
最近のトレンドである Page Object Model (POM) も、やりすぎればただの抽象化の迷宮になる。まずは、テストコードを「ユーザーのストーリー」として記述し、共通処理だけを関数に切り出す。それだけでいい。
| 改善項目 | 目的 |
|---|---|
| シャarding導入 | 実行時間の短縮(物理的な解決) |
| アサートの厳格化 | Flakyの撲滅(論理的な解決) |
| デフォルト設定の維持 | 保守コストの最小化(運用的な解決) |
テストコードは、書いたその日から負債になるか、資産になるかの分かれ道に立っている。深夜に起こされたくなければ、まずは「不安定なテスト」の放置をやめることから始めようぜ。コードは裏切らない。正しい設計さえしていればな。