0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Playwright × Docker × GitHub Actions】CIでE2Eテストが失敗する時の完全解決ガイド

Posted at

Docker Compose で構築した Next.js アプリケーションに対し、GitHub Actions 上で Playwright による E2E テストを実行しようとしたところ、ネットワークエラーやタイムアウトに悩まされました。

試行錯誤の末に安定して動作する構成にたどり着いたので、その「解決策」を共有します。

発生していた問題

GitHub Actions で docker compose を立ち上げ、Playwright からアクセスしようとすると以下のエラーが発生しました。

  1. net::ERR_ADDRESS_UNREACHABLE / net::ERR_CONNECTION_REFUSED
    • コンテナ間の通信がうまくできない。
  2. TimeoutError (30000ms)
    • 画面が真っ白のまま、要素が見つからずにテストが落ちる。
  3. Exit code 124 (timeout)
    • フロントエンドの起動待機スクリプトが終わらない。

原因と解決策

主な原因は以下の4点でした。

  1. ネットワークの指定ミス(固定IPやlocalhostの使用)
  2. Next.js のコンテナ設定(外部アクセスの拒否)
  3. コンテナ再起動による待機無効化docker compose run の挙動)
  4. CI環境のスペック不足によるタイムアウト

それぞれの解決策を解説します。


1. 固定IPをやめ、サービス名でアクセスする

当初は ipv4_address で固定IPを指定していましたが、CI環境ではネットワークドライバの挙動により不安定になることがあります。また、Dockerネットワーク内では localhost は「自分自身」を指すため、Playwrightコンテナから http://localhost:3000 へは繋がりません。

解決策:
Docker Compose の DNS解決(サービスディスカバリ)を利用し、サービス名でアクセスします。

tests/sample.spec.ts

// × 修正前
// await page.goto("http://10.254.xx.xx:3000/...");
// await page.goto("http://localhost:3000/...");

// 〇 修正後:docker-compose.yml のサービス名 "frontend" を指定
await page.goto("http://frontend:3000/test");

2. Next.js を 0.0.0.0 で起動する

Next.js (v13.4以降など) はデフォルトで localhost (127.0.0.1) でリッスンします。これはコンテナ内からはアクセスできますが、コンテナ外(Playwrightコンテナ)からのアクセスを拒否してしまいます。

解決策:
環境変数 HOSTNAME=0.0.0.0 を設定して、外部からのアクセスを受け付けるようにします。また、ボリュームマウントで node_modules が消えないように保護します。

docker-compose.yml

  frontend:
    # ...
    environment:
      - HOSTNAME=0.0.0.0 # 重要: これがないと接続拒否される
    volumes:
      - ./frontend:/frontend
      - /frontend/node_modules # 重要: コンテナ内のモジュールを守る

3. コンテナの再起動を防ぐ (--no-deps)

これが一番のハマりポイントでした。
GitHub Actions で curl コマンドを使って「フロントエンドが起動するまで待機」するステップを入れていましたが、その後のテスト実行コマンドでコンテナが再起動してしまい、待機した意味がなくなっていました。

  • docker compose run playwright ... を実行すると、依存関係にある frontend もデフォルトで再作成(Recreate)される場合がある。
  • 再起動すると Next.js のコンパイルが最初からになり、テストのタイムアウトに間に合わない。

解決策:
--no-deps オプションをつけて、すでに起動・待機済みのコンテナをそのまま使います。

.github/workflows/test.yml

      # 1. 起動して待つ
      - name: Wait for Frontend
        run: timeout 120s bash -c 'until curl --silent --fail http://localhost:3000; do sleep 5; done'

      # 2. 再起動させずにテスト実行 (--no-deps)
      - name: Run Playwright tests
        run: docker compose run --rm --no-deps playwright npx playwright test

4. タイムアウト時間の延長と環境変数

CI環境(GitHub Actions)はローカルマシンよりスペックが低く、レンダリングに時間がかかります。デフォルトのタイムアウト(5秒や30秒)では失敗することがあります。
また、APIのURLなどの環境変数がCI上で設定されていないと、アプリが正しく動きません。

tests/sample.spec.ts

test("テスト", async () => {
  test.setTimeout(60000); // テスト全体のタイムアウトを60秒に延長
  // ...
  await expect(locator).toBeVisible({ timeout: 30000 }); // 要素待機も長めに
});

最終的なコード構成

docker-compose.yml

version: "3.3"

services:
  playwright:
    build:
      context: .
      dockerfile: "./playwright/Dockerfile"
    volumes:
      - ./playwright:/app
      - /app/node_modules
    depends_on:
      - frontend

  frontend:
    build:
      context: .
      dockerfile: "./frontend/Dockerfile.next"
    volumes:
      - ./frontend:/frontend
      - /frontend/node_modules
    ports:
      - "3000:3000"
    environment:
      - HOSTNAME=0.0.0.0
      - NEXT_PUBLIC_APP_API_URL_8080
      - NEXT_PUBLIC_BASE_URL

GitHub Actions Workflow (.github/workflows/ci.yml)

name: E2E Test

on: [push]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Start services
        # 必要な環境変数をここで注入
        env:
          NEXT_PUBLIC_APP_API_URL_8080: "http://api-server-url" 
        run: docker compose up -d

      - name: Wait for Frontend
        run: |
          echo "Waiting for frontend..."
          # ホスト側からlocalhost:3000を監視
          timeout 120s bash -c 'until curl --silent --fail http://localhost:3000; do echo "Retrying..."; sleep 5; done'

      - name: Show Frontend Logs (on failure)
        if: failure()
        run: docker compose logs frontend

      - name: Run Playwright tests
        # --no-deps でコンテナ再起動を防止
        run: docker compose run --rm --no-deps playwright npx playwright test

      - name: Upload screenshots
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-screenshots
          path: playwright/images/
          retention-days: 5

まとめ

Docker × CI 環境での E2E テストを安定させるためのポイントは以下の通りです。

  1. URLはサービス名で指定 (http://frontend:3000)。
  2. Next.js は 0.0.0.0 で起動 して外部アクセスを許可。
  3. 起動待機 (Wait) を入れる
  4. --no-deps を使って、待機後のコンテナ再起動を防ぐ。
  5. CI用のタイムアウト設定 を長めにとる。

これで、「ローカルでは動くのにCIだけ落ちる」現象から脱出できました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?