【アンチパターン】Selenium時代の悪習。これだとテストが死ぬ。

深夜2時、コーヒー4杯目のカフェインで心拍数が跳ね上がり、デプロイボタンを押す指が震える。この感覚、エンジニアなら嫌というほど分かるだろ?「本当に動くか?」という根拠のない不安を抱えたまま本番へコードを流し込むのは、もはやロシアンルーレットだ。

「自動テストさえ入れれば安心」と高を括っていた俺は、Playwrightという名の深い迷宮に足を踏み入れ、数々のFlaky Test(不安定なテスト)にボコボコにされた。今日は、その泥沼からどう這い上がり、GitHub Actionsで鉄壁のCI/CDを構築したのか、その「現場の血」を晒す。


Seleniumの悪夢と、Playwrightという「救い」

昔、Seleniumでテストを書いていた頃は地獄だった。`time.sleep(5)`を呪文のようにコードの随所に埋め込み、それでも「要素が見つかりません」で落ちる。テストを直すためにテストを書くという本末転倒な日々。

Playwrightが神なのは、Auto-waitingが標準搭載されている点だ。要素が表示されるまで泥臭く待機してくれる。これだけで工数は半分以下になる。

# 【アンチパターン】Selenium時代の悪習。これだとテストが死ぬ。
def test_bad_login(page: Page):
    page.goto("/login")
    page.click("#submit") # 読み込み前にクリックして即死
    time.sleep(3)         # 祈りの待機。バグの温床。
    expect(page.locator(".error")).to_be_visible()

# 【ベストプラクティス】Web-First Assertionsで待機を任せる
def test_good_login(page: Page):
    page.goto("/login")
    page.click("#submit")
    # Playwrightが勝手に待ってくれる。これが本来の姿。
    expect(page.locator(".error")).to_be_visible(timeout=5000)


Flaky Testの迷宮:なぜ「昨日まで」は通ったのか?

一番ハマったのは、SPAの非同期処理だ。例えば「ボタンを押すとAPIを叩き、レスポンスを待ってからモーダルを開く」というフロー。`page.click()`だけでは、APIの完了を待たずに次のアサーションへ進んでしまい、テストが落ちる。

再現シナリオ:
1. ユーザーが「保存」をクリック。
2. JSがAPIリクエストを発行。
3. Playwrightが即座にDOMの変化(成功メッセージ)を探しに行くが、まだAPIレスポンスが返っておらず、DOMが更新されていない。
4. 「要素がない」とエラー。

これを解決するのは`waitForResponse`一択だ。

// APIのレスポンスを「待つ」という強い意志を持つ
await Promise.all([
  page.waitForResponse(resp => resp.url().includes('/api/save') && resp.status() === 200),
  page.click('#save-btn') // ここでクリックした瞬間、API完了まで同期的に待機する
]);

この書き方に変えた瞬間、成功率は90%から99.9%に跳ね上がった。残りの0.1%? それはネットワークの機嫌が悪いときもある。人間だって機嫌が悪いときがあるだろ?


GitHub Actionsで構築する「鉄壁の守護神」

ローカルの緑色は自己満足だ。GitHub Actionsでプルリクのたびに叩き込む。ここで重要なのは、Dockerサービスコンテナを活用することだ。

jobs:
  test:
    runs-on: ubuntu-latest
    services:
      db:
        image: postgres:15
        env:
          POSTGRES_DB: test_db
        ports:
          - 5432:5432
    steps:
      - uses: actions/checkout@v3
      - name: Run Playwright
        run: npx playwright test
        env:
          DATABASE_URL: postgresql://postgres@localhost:5432/test_db
      - uses: actions/upload-artifact@v3
        if: always() # 落ちた時こそ真価を発揮する
        with:
          name: trace-report
          path: playwright-report/

`docker-compose`をわざわざ入れなくても、GitHub Actionsの`services`を使えばテストごとにクリーンなDBが立ち上がる。ゴミデータが残ってテストが落ちる「あのイライラ」から完全に解放された。


結論:テストは「心の平穏」への投資

Playwrightを導入して半年。開発速度は落ちたか? むしろ逆だ。「コードを壊しても、CIがすぐに教えてくれる」という安心感のおかげで、リファクタリングの速度が劇的に上がった。

  • 導入前: デプロイ後のバグ修正に2時間。
  • 導入後: CIが即座にエラーを指摘し、修正に5分。
テストコードは、書くコストよりも「壊れた本番環境を深夜に直す絶望」の方が遥かに高い。今の俺は、テストが全て緑色に光るのを確認してから、ようやく安心してビールを飲めるようになった。

この「緑色」こそが、エンジニアのメンタルを支える最強の安定剤だ。お前らも、深夜のデプロイで震えるのはもう終わりにしようぜ。