
Webアプリケーション開発において、手動でのブラウザテストは時間がかかり、見落としも発生しやすいものです。この記事では、VPS環境でPuppeteerとヘッドレスChromiumを使って、複数プロジェクトで再利用可能な汎用E2Eテストフレームワークを構築する方法を紹介します。
この記事で学べること
- VPS環境でのヘッドレスChromiumのセットアップ
- Puppeteerを使ったブラウザ自動操作
- 複数プロジェクトで再利用可能なテストフレームワークの設計
- Laravel/Filament などのWebアプリケーションの自動テスト
環境
- OS: Ubuntu 22.04 LTS (VPS)
- Node.js: v23.9.0
- Puppeteer: v23.0.0
- Chromium: 140.0.7339.185
アーキテクチャ
/home/user/server/
├── e2e-testing/ # 汎用テストフレームワーク
│ ├── bin/
│ │ └── test-runner.js # CLIツール
│ ├── lib/
│ │ ├── browser.js # ブラウザ接続管理
│ │ ├── auth.js # 認証ヘルパー
│ │ ├── checker.js # エラーチェック
│ │ └── reporter.js # レポート生成
│ └── package.json
│
└── domains/example.com/project/
└── e2e-tests/ # プロジェクト固有設定
├── config.json # テスト設定
├── screenshots/ # スクリーンショット
└── reports/ # テストレポート
Step 1: Chromiumのインストールとセットアップ
Chromiumインストール
# Chromiumブラウザをインストール
sudo apt-get update
sudo apt-get install -y chromium-browser
# バージョン確認
chromium-browser --version
# Chromium 140.0.7339.185 Built on Ubuntu, running on Ubuntu 22.04
日本語フォントのインストール(重要!)
VPS環境のChromiumでは日本語フォントがデフォルトでインストールされていないため、日本語が文字化け(□□□□のような表示)してしまいます。スクリーンショットで日本語を正しく表示するために、日本語フォントをインストールします:
# 日本語フォントをインストール
sudo apt-get install -y fonts-noto-cjk fonts-noto-cjk-extra fonts-ipafont fonts-ipaexfont
インストールされるフォント:
fonts-noto-cjk
: GoogleのNoto Sans CJK(日中韓統合フォント)fonts-noto-cjk-extra
: Noto CJKの追加ウェイトfonts-ipafont
: IPA フォント(日本語標準フォント)fonts-ipaexfont
: IPA拡張フォント
フォントをインストールした後は、Chromiumを再起動する必要があります:
# Chromiumを停止
pkill -f chromium
# 再起動
chromium-browser \
--headless \
--remote-debugging-port=9222 \
--remote-debugging-address=127.0.0.1 \
--no-sandbox \
--disable-gpu &
ヘッドレスモードで起動
VPS環境ではGUIがないため、ヘッドレスモード(画面なし)で起動します:
# ヘッドレスモードで起動(バックグラウンド実行)
chromium-browser \
--headless \
--remote-debugging-port=9222 \
--remote-debugging-address=127.0.0.1 \
--no-sandbox \
--disable-gpu &
オプション説明:
--headless
: GUI不要のヘッドレスモード--remote-debugging-port=9222
: DevToolsプロトコル用ポート--remote-debugging-address=127.0.0.1
: localhostのみアクセス許可(セキュリティ重要)--no-sandbox
: サンドボックス無効化(VPS環境で必要な場合)--disable-gpu
: GPU無効化(軽量化)
セキュリティ確認(重要!)
ポート9222がlocalhostのみでリッスンしていることを確認します:
# ポート9222のバインドアドレスを確認
netstat -tlnp | grep 9222
# または
ss -tlnp | grep 9222
正しい設定(安全):
tcp 0 0 127.0.0.1:9222 0.0.0.0:* LISTEN
→ 127.0.0.1
になっていればOK(localhostからのみアクセス可能)
危険な設定(絶対に避ける):
tcp 0 0 0.0.0.0:9222 0.0.0.0:* LISTEN
→ 0.0.0.0
は全てのIPアドレスからアクセス可能を意味します
なぜlocalhost制限が必要か?
Chrome DevToolsプロトコル(ポート9222)は、ブラウザへの完全な制御権限を提供します。外部に公開すると:
- ❌ 誰でもブラウザを操作可能
- ❌ Cookie/セッションの盗聴
- ❌ 任意のページへのアクセス
- ❌ フォーム入力やボタンクリックの実行
- ❌ スクリーンショットの取得
そのため、必ずlocalhost(127.0.0.1)からのみアクセスできるように制限する必要があります。
Step 2: Node.jsとnpmのセットアップ
nvmでNode.jsインストール
# nvm (Node Version Manager) インストール
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
# シェルを再起動 or 以下を実行
source ~/.bashrc
# Node.js最新版をインストール
nvm install node
# バージョン確認
node --version # v23.9.0
npm --version # 10.9.2
Step 3: 汎用E2Eテストフレームワークの構築
プロジェクト初期化
# フレームワーク用ディレクトリ作成
mkdir -p ~/server/e2e-testing
cd ~/server/e2e-testing
# package.json作成
npm init -y
依存パッケージインストール
npm install puppeteer-core chalk commander
パッケージ説明:
puppeteer-core
: Puppeteerのコア機能(Chromium同梱なし)chalk
: ターミナル出力の色付けcommander
: CLIツール作成
コアライブラリ作成 – browser.js
ブラウザ接続管理を行うライブラリを作成します(lib/browser.js
):
const puppeteer = require('puppeteer-core');
class BrowserManager {
constructor(config = {}) {
this.config = {
wsEndpoint: config.wsEndpoint || 'ws://127.0.0.1:9222',
defaultTimeout: config.defaultTimeout || 30000,
...config
};
this.browser = null;
}
// ブラウザに接続
async connect() {
this.browser = await puppeteer.connect({
browserWSEndpoint: this.config.wsEndpoint,
defaultViewport: { width: 1280, height: 800 }
});
return this.browser;
}
// 新しいページを作成
async newPage() {
const page = await this.browser.newPage();
page.setDefaultTimeout(this.config.defaultTimeout);
// エラーログ収集
page.on('console', msg => {
if (msg.type() === 'error') {
console.log('[Console Error]:', msg.text());
}
});
page.on('pageerror', error => {
console.error('[Page Error]:', error.message);
});
return page;
}
// ブラウザから切断
async disconnect() {
if (this.browser) {
await this.browser.disconnect();
}
}
}
module.exports = BrowserManager;
認証ヘルパー – auth.js
FilamentPHPなどの管理画面へのログイン処理を簡単にするヘルパーを作成します(lib/auth.js
):
class AuthHelper {
constructor(page, config) {
this.page = page;
this.config = config;
}
// FilamentPHPログイン
async loginFilament() {
const { loginUrl, credentials } = this.config;
const baseUrl = this.config.baseUrl || '';
await this.page.goto(`${baseUrl}${loginUrl}`, {
waitUntil: 'networkidle2'
});
// メールアドレス入力
await this.page.waitForSelector('input[type="email"]');
await this.page.type('input[type="email"]', credentials.email);
// パスワード入力
await this.page.type('input[type="password"]', credentials.password);
// ログインボタンクリック
await Promise.all([
this.page.waitForNavigation({ waitUntil: 'networkidle2' }),
this.page.click('button[type="submit"]')
]);
console.log('✓ ログイン成功');
return true;
}
}
module.exports = AuthHelper;
Step 4: プロジェクトでの使用方法
設定ファイルの作成
プロジェクトディレクトリに設定ファイルe2e-tests/config.json
を作成します:
{
"baseUrl": "https://example.com",
"auth": {
"type": "filament",
"loginUrl": "/admin/login",
"credentials": {
"email": "admin@example.com",
"password": "password"
}
},
"pages": [
{
"name": "Dashboard",
"url": "/admin",
"checks": ["noJsErrors", "noServerErrors", "hasContent"]
},
{
"name": "Users",
"url": "/admin/users",
"checks": ["noJsErrors", "noServerErrors", "hasContent"]
}
],
"browser": {
"wsEndpoint": "ws://127.0.0.1:9222/devtools/browser/...",
"defaultTimeout": 30000
},
"screenshots": {
"enabled": true,
"directory": "./e2e-tests/screenshots"
}
}
テスト実行
# テスト実行
node ~/server/e2e-testing/bin/test-runner.js run
# または、npmスクリプトに追加
npm run e2e-test
トラブルシューティング
WebSocket接続エラー
エラーメッセージ:
✗ ブラウザ接続エラー: Unexpected server response: 404
原因: Chromiumを再起動すると、WebSocketエンドポイントのURLが変わります。
解決方法:
最新のWebSocketエンドポイントURLを取得:
curl -s http://127.0.0.1:9222/json/version | grep webSocketDebuggerUrl
出力されたURLをconfig.json
のbrowser.wsEndpoint
に設定します。
スクリーンショットで日本語が文字化け
症状: スクリーンショットで日本語が □□□□ のように表示される
原因: VPS環境に日本語フォントがインストールされていない
解決方法:
# 日本語フォントをインストール
sudo apt-get install -y fonts-noto-cjk fonts-noto-cjk-extra fonts-ipafont fonts-ipaexfont
# Chromiumを再起動
pkill -f chromium
chromium-browser --headless --remote-debugging-port=9222 --remote-debugging-address=127.0.0.1 --no-sandbox --disable-gpu &
node\r エラー
エラーメッセージ:
/usr/bin/env: 'node\r': そのようなファイルやディレクトリはありません
原因: Windows環境で作成されたファイルのCRLF改行コード
解決方法:
sed -i 's/\r$//' /path/to/test-runner.js
応用例
CI/CDパイプラインに組み込む
# GitHub Actions例
name: E2E Tests
on: [push]
jobs:
e2e-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '18'
- name: Install Chromium
run: sudo apt-get install -y chromium-browser
- name: Start Chromium
run: chromium-browser --headless --remote-debugging-port=9222 &
- name: Run E2E Tests
run: node ~/server/e2e-testing/bin/test-runner.js run
定期実行 (cron)
# 毎日午前2時にテスト実行
0 2 * * * cd ~/server/domains/example.com/myproject && node ~/server/e2e-testing/bin/test-runner.js run
まとめ
この記事では、VPS環境でPuppeteerとヘッドレスChromiumを使った汎用E2Eテストフレームワークの構築方法を紹介しました。
メリット:
- ✅ 複数プロジェクトで再利用可能
- ✅ 設定ファイルベースで簡単カスタマイズ
- ✅ HTMLレポート・スクリーンショット自動生成
- ✅ CI/CD統合が容易
- ✅ 日本語コンテンツにも対応
実装時のポイント:
- 日本語フォントのインストールは必須
- Chromium再起動時はWebSocketエンドポイントの更新が必要
- セッション管理に注意(Cookie/キャッシュのクリア)
- 改行コードはLF(UNIX形式)に統一
次のステップ:
- より詳細なエラー検出ロジックの追加
- Slack/Email通知機能の追加
- パフォーマンス測定機能の追加
- 並列実行対応