CI 環境構築で直面した E2E テスト自動化の壁 〜Google の bot 対策による脅威のディフェンス力〜
はじめに
Next.js と Rails を使ってオリジナルの Web アプリを開発しています。
Playwright を導入し E2E テストの実装は問題なくできましたが、その後 CI でのテストの自動化がうまくいかず数日ハマってしまいました。今回の記事ではその原因と結果についてまとめています。
Playwright 導入については以下記事にまとめています。
CI 環境構築
ローカル環境下でパスした E2E テストの自動化に取り組みました。
GitHub Actions に yml ファイルを用意し自動化のためのワークフローを記述しました。
name: "Frontend E2E Test"
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
jobs:
e2e-test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:14.8
ports:
- "5432:5432"
env:
POSTGRES_DB: rails_test
POSTGRES_USER: rails
POSTGRES_PASSWORD: password
env:
RAILS_ENV: test
DATABASE_URL: "postgres://rails:password@localhost:5432/rails_test"
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Ruby and gems
uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0
with:
ruby-version: "3.2.1"
bundler-cache: true
- name: Install libvips
run: sudo apt install -y libvips
working-directory: ./backend
- name: Install dependencies
run: |
cd backend
bundle install
working-directory: ./backend
- name: Set up database schema and Start Rails server
run: |
bundle exec rails db:schema:load
bundle exec rails db:reset RAILS_ENV=test
bundle exec rails s &
sleep 30
working-directory: ./backend
- name: Setup Node.js 18.x
uses: actions/setup-node@v3
with:
node-version: 18.x
- name: Install dependencies
run: npm ci
working-directory: ./frontend
- name: Install Playwright Browsers
run: npx playwright install --with-deps
working-directory: ./frontend
- name: Start Next.js server
run: |
npm run dev &
sleep 30
working-directory: ./frontend
- name: Run Playwright tests
run: npx playwright test
working-directory: ./frontend/playwright
しかし、エラーが発生しテストが回りません。
Error occurred during API request: AxiosError: connect ECONNREFUSED ::1:3000
原因と結論
今回発生したエラーの原因、そして結論を説明します。
今回エラーが発生している箇所は、Google ログイン認証のステップであることがわかりました。
テスト用に準備した Google アカウントの Email を利用しログインを実行する際、Google 側の bot 対策に引っかかり Google ログイン認証を通過できない状況です。ローカル環境では下記エラーは起きません。しかし、GitHub Actions CI 環境下においてはエラーが発生する状況です。
bot と疑われログインが拒否された時にブラウザに表示されるエラー内容:

テスト用アカウントに届いた Google からの通知内容:

対応として、 bot と認定されないように Google 認証を行う方法、また Google 認証ログイン自体をモック化し対応する方法も検討しましたが、どちらも有効な手立てが見つかりませんでした。
そのため、CI 環境下での E2E テストは断念する結論に至りました。
E2E テストは、ローカル環境下では問題なくパスできるため、動作確認は担保されていると判断したためです。
デバッグ
結果としては、E2E テストを CI 環境下では実施しない判断となりましたが、「CI 環境構築において Playwright を使った E2E テスト」の実装に伴って取り組んだ内容を記録として残します。
環境変数の管理
next サーバーで使用する環境変数が正しく設定ができていなかったため見直しました。
// .github/workflows/frontend-test.yml
- name: Start Next.js server
run: |
npm run dev &
env:
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
NEXTAUTH_URL: ${{ secrets.NEXTAUTH_URL }}
NEXTAUTH_URL_INTERNAL: ${{ secrets.NEXTAUTH_URL_INTERNAL }}
NEXT_PUBLIC_GEOCODING_API_KEY: ${{ secrets.NEXT_PUBLIC_GEOCODING_API_KEY }}
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY: ${{ secrets.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY }}
NEXT_PUBLIC_RAILS_API_URL: ${{ secrets.NEXT_PUBLIC_RAILS_API_URL }}
NEXT_SECRET: ${{ secrets.NEXT_SECRET }}
RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
working-directory: ./frontend

環境変数は取得できているか?
環境変数にちゃんと欲しい値が渡っているか確認しました。
console.log で確認する例:
// frontend/playwright/global-setup.ts import { userEmail, userPassword, baseURL } from "playwright/config/index"; console.log("========================================================"); console.log(userEmail); console.log(userPassword); console.log(baseURL); console.log("========================================================");
ひとつ注意点ですが、ローカルではちゃんと値の表示は確認できますが、GitHub Actions の secrets に保存した値は console に出力したときに、***とマスクされて出力されます。GitHub 上の仕様かと思われます。
Run npx playwright test ======================================================== *** *** *** ========================================================
デバッグ用で撮影したスクショを GitHub に保存する設定
ローカル環境下においてはスクショを保存し確認できていたのですが、GitHub 上で確認ができておらずデバッグを困難にしていました。
下記のプログラムで GitHub 上でも確認が可能になります。
参考: ワークフロー データを成果物として保存する - GitHub Docs
// .github/workflows/frontend-test.yml
- name: Archive screenshots
uses: actions/upload-artifact@v3
with:
name: screenshots
path: ./frontend/playwright/screenshots
if: always()
全画面をスクショする場合、以下を任意の箇所へ配置しておきます。
await page.screenshot({ path: "playwright/screenshots/error.png", fullPage: true, });
GitHub 上で確認する時:

上記のif: always()ですが、他のジョブが成功したかに関わらず、完了後に常に実行されます。