フロントエンドの自動テストは「書く」な、「守る」仕組みを設計しろ
「昨日直したはずの機能が、また動かなくなっている」。
開発現場でこの絶望を何度味わえば気が済むのか。手動テストで画面をポチポチと遷移させる時間は、エンジニアにとって最も生産性の低いコストだ。Playwrightを導入して自動化する? それはスタートラインに過ぎない。真の地獄は、テストが書かれたその瞬間から始まる。
UI変更のたびに壊れるテストコードを修正し、CIが落ちるたびに原因を追う。そんな「テストの奴隷」から脱却するための、泥臭い知見を共有する。
1. セレクタの「美学」を捨て、堅牢さを選べ
CSSセレクタで `div > div:nth-child(2) > button` なんて書いてる奴は、今すぐキーボードから手を離せ。デザインが変わるたびにテストが死ぬのは、設計が甘いからだ。
鉄則:責務を分離する
テスト用に `data-testid` を振るのは定石だが、それだけで満足してはいけない。アクセシビリティの観点から、Playwrightの `getByRole` を優先的に使うべきだ。// 悪い例:CSS依存。変更に弱すぎる
await page.locator('.btn-login').click();
// 良い例:data-testidで明示的に指定
await page.getByTestId('login-button').click();
// ベストプラクティス:アクセシブルな役割で取得
// ユーザーの操作体験とテストが一致し、UI構造に依存しにくい
await page.getByRole('button', { name: /ログイン/i }).click();
`getByRole` を使うことで、テストが「ボタンの役割」を理解し、マークアップ構造が多少変わっても壊れにくいテストが完成する。これは単なるコードの書き方ではなく、UIに対する設計思想だ。
2. APIモックの「幻想」と向き合う
「バックエンドも含めてテストしないと不安」という声を聞くが、E2Eの目的を履き違えてはいけない。UIの確認が目的なら、APIレスポンスはモックすべきだ。
MSWか、Playwrightのrouteか?
- MSW (Mock Service Worker): ネットワークレベルでインターセプトするため、ブラウザ側の実装と共通化できるのが最大の強み。
- Playwright `route`: テストコード内で完結するため、環境構築が極めて楽。
// 意図的にエラーを発生させて、UIの挙動を検証する
await page.route('**/api/user', route => route.fulfill({
status: 500,
contentType: 'application/json',
body: JSON.stringify({ message: 'Internal Server Error' }),
}));
3. GitHub Actions:並列実行の「死の罠」
CIでテストを回す際、`workers` を増やせば速くなると思ったら大間違いだ。リソースの競合でテストが不安定になり、結局「再実行ボタン」を押す回数が増える。
賢いCI戦略
GitHub Actionsで無料枠を使いつつ、安定稼働させるための設定はこれだ。# .github/workflows/e2e.yml
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Playwright
run: npx playwright test --workers=2 --max-failures=5
- `--workers`: 無料枠なら2〜4が限界。それ以上はメモリ不足でCI自体が死ぬ。
- `--max-failures`: 最初の数件が失敗したら即座に停止させる。無駄なリソースを回さないための防衛線だ。
- `Shard`機能: テスト数が増えてきたら、`--shard=1/3` のようにテストを分割して並列実行する。これが大規模プロジェクトでの唯一の解法だ。
4. 自動化を「文化」にするために
最後に一つ、技術以上に大切なことを伝える。
自動化の最大の敵は「壊れたテストを放置する文化」だ。テストが落ちているのに無視してマージするチームに、自動化の価値はない。テストが落ちたら、「なぜ落ちたか」を議論し、コードを修正するまでをワンセットのフローとして組み込むこと。
「俺なら一瞬で書ける」なんて慢心は捨てる。チーム全員がテストコードを「自分たちの資産」として管理し、壊れたら即座に修復する。この泥臭いサイクルこそが、プロダクトを堅牢に保つ唯一の道だ。
自動化は、書いた後のメンテナンスこそが本番。今日から、その意識でコードに向き合ってみろ。