開発・技術選定

業務システムに E2E テストを入れる — Playwright で「壊れたら気づく」状態を作る

単体テストが通っていても、画面は壊れます。
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クラスに依存しない)
  • 各テストが自分でデータを用意する
  • 失敗時のスクリーンショットとトレースを必ず残す