単体テストが通っていても、画面は壊れます。
JavaScript のエラー、CSS の崩れ、遷移の断絶は、E2E でしか捕まりません。
どこまで書くか
E2E は書きすぎると保守できなくなります。
「これが壊れたら業務が止まる」経路だけに絞ります。
- ログイン → 一覧 → 詳細
- 新規作成 → 保存 → 一覧に反映される
- 承認フロー(申請 → 承認 → 完了)
- 帳票のダウンロード
網羅は捨てます。主要導線が生きているかの確認装置と割り切ります。
不安定にしないための書き方
E2E が嫌われる最大の理由は、たまに落ちることです。
原因のほとんどは待ち方にあります。
// 悪い例:固定時間で待つ(環境が変わると壊れる)
await page.waitForTimeout(3000);
// 良い例:状態を待つ
await expect(page.getByRole("heading", { name: "注文一覧" })).toBeVisible();
要素の指定も、CSS クラスではなく役割やラベルで取ります。
// 壊れやすい
await page.click(".btn-primary.mt-4");
// 壊れにくい
await page.getByRole("button", { name: "保存" }).click();
デザイン変更でテストが落ちる状態だと、誰も直さなくなります。
テストデータの独立性
前のテストの結果に依存すると、実行順で結果が変わります。
各テストが自分でデータを作るのが鉄則です。
test.beforeEach(async ({ request }) => {
await request.post("/test-api/reset/", { data: { fixture: "orders" } });
});
テスト専用のリセット用エンドポイントは、
本番では必ず無効化します(設定で分岐させ、テストで確認します)。
落ちたときに原因が分かるように
// playwright.config.js
use: {
screenshot: "only-on-failure",
video: "retain-on-failure",
trace: "retain-on-failure",
}
CI で落ちたとき、スクリーンショットと操作トレースが残るかどうかで
調査時間がまったく違います。
CI に組み込む
- run: npx playwright test
# 失敗したら成果物を保存
- uses: actions/upload-artifact@v4
if: failure()
with: { name: playwright-report, path: playwright-report/ }
本番デプロイの前段に置き、通らなければ止めるようにしています。
まとめ
- 主要導線だけ書く。網羅は目指さない
waitForTimeoutを使わず、状態を待つ- 要素は役割・ラベルで取る(CSSクラスに依存しない)
- 各テストが自分でデータを用意する
- 失敗時のスクリーンショットとトレースを必ず残す