Playwright のテストランナー活用術

現代の Web 開発において、テストの自動化は品質保証の要となっています。特に Playwright は、クロスブラウザテストを効率的に実行できる強力なツールとして注目を集めています。
しかし、多くの開発者が直面する課題があります。テストの実行時間が長すぎる、不安定なテストが頻繁に失敗する、CI/CD パイプラインでの実行が非効率であるなど、実際の開発現場では様々な問題が発生します。
この記事では、Playwright のテストランナーを最大限に活用する方法を、実践的な観点から詳しく解説していきます。基本機能から高度な最適化テクニックまで、段階的に理解を深められる構成になっています。
テストランナーの基本機能
テストファイルの実行方法
Playwright のテストランナーは、直感的で柔軟な実行方法を提供しています。まずは基本的な実行コマンドから始めましょう。
bash# 基本的なテスト実行
npx playwright test
# 特定のテストファイルを実行
npx playwright test login.spec.ts
# テスト名でフィルタリングして実行
npx playwright test --grep "ログイン機能"
テストファイルの構造を理解することで、より効率的な実行が可能になります。
typescript// tests/login.spec.ts
import { test, expect } from '@playwright/test';
// テストグループの定義
test.describe('ログイン機能', () => {
// 各テストケース
test('正常なログイン', async ({ page }) => {
await page.goto('/login');
await page.fill(
'[data-testid="email"]',
'user@example.com'
);
await page.fill(
'[data-testid="password"]',
'password123'
);
await page.click('[data-testid="login-button"]');
await expect(page).toHaveURL('/dashboard');
});
});
並列実行の仕組み
Playwright の真の力を発揮するのが並列実行機能です。複数のテストを同時に実行することで、大幅な時間短縮を実現できます。
typescript// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
// 並列実行の設定
workers: 4, // 同時実行数
// プロジェクト別の設定
projects: [
{
name: 'chromium',
use: { browserName: 'chromium' },
},
{
name: 'firefox',
use: { browserName: 'firefox' },
},
{
name: 'webkit',
use: { browserName: 'webkit' },
},
],
});
並列実行時の注意点として、テスト間の独立性を保つことが重要です。
typescript// テスト間の独立性を保つためのベストプラクティス
test.describe('ユーザー管理', () => {
// 各テスト前にデータベースをクリーンアップ
test.beforeEach(async ({ page }) => {
await page.goto('/admin/users');
// テストデータの初期化
});
test('ユーザー作成', async ({ page }) => {
// テストロジック
});
test('ユーザー削除', async ({ page }) => {
// 独立したテストロジック
});
});
テストフィルタリング機能
大規模なテストスイートでは、必要なテストだけを実行するフィルタリング機能が不可欠です。
bash# タグによるフィルタリング
npx playwright test --grep @smoke
npx playwright test --grep-invert @slow
# ファイル名によるフィルタリング
npx playwright test **/login*.spec.ts
# 複数条件の組み合わせ
npx playwright test --grep "ログイン" --project=chromium
テストファイルでのタグ付け方法:
typescript// タグを使用したテストの分類
test('@smoke @critical ログイン機能', async ({ page }) => {
// 重要なテストケース
});
test('@slow @integration ユーザー登録フロー', async ({
page,
}) => {
// 時間のかかる統合テスト
});
// テストグループ全体にタグを適用
test.describe('@e2e エンドツーエンドテスト', () => {
test('購入フロー', async ({ page }) => {
// E2Eテストの実装
});
});
高度な実行オプション
ヘッドレスモードとヘッドフルモードの使い分け
Playwright では、実行環境に応じてヘッドレスモードとヘッドフルモードを使い分けることができます。
typescript// playwright.config.ts
export default defineConfig({
use: {
// ヘッドレスモードの設定
headless: true, // CI/CD環境ではtrue
// ヘッドフルモードでの開発時設定
// headless: false, // ローカル開発時はfalse
},
// 環境別の設定
projects: [
{
name: 'development',
use: { headless: false },
},
{
name: 'production',
use: { headless: true },
},
],
});
デバッグ時の便利な設定:
typescript// デバッグ用の設定
export default defineConfig({
use: {
headless: false,
slowMo: 1000, // 動作を遅くして確認
devtools: true, // 開発者ツールを自動で開く
},
});
ブラウザ別実行戦略
異なるブラウザでの動作確認は、Web アプリケーションの品質保証において重要です。
typescript// ブラウザ別の設定
export default defineConfig({
projects: [
{
name: 'chromium',
use: {
browserName: 'chromium',
viewport: { width: 1280, height: 720 },
},
},
{
name: 'firefox',
use: {
browserName: 'firefox',
viewport: { width: 1280, height: 720 },
},
},
{
name: 'webkit',
use: {
browserName: 'webkit',
viewport: { width: 1280, height: 720 },
},
},
],
});
モバイルブラウザのシミュレーション:
typescript// モバイルデバイスのシミュレーション
export default defineConfig({
projects: [
{
name: 'mobile-chrome',
use: {
browserName: 'chromium',
...devices['iPhone 12'],
},
},
{
name: 'mobile-safari',
use: {
browserName: 'webkit',
...devices['iPhone 12'],
},
},
],
});
カスタム実行環境の構築
プロジェクト固有の要件に応じて、カスタム実行環境を構築できます。
typescript// カスタム実行環境の設定
export default defineConfig({
// グローバル設定
timeout: 30000,
expect: {
timeout: 5000,
},
// カスタムフィクスチャの定義
use: {
baseURL:
process.env.BASE_URL || 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
// 環境変数による設定
projects: [
{
name: 'staging',
use: {
baseURL: 'https://staging.example.com',
},
},
{
name: 'production',
use: {
baseURL: 'https://example.com',
},
},
],
});
パフォーマンス最適化
並列実行数の調整
適切な並列実行数を設定することで、リソースを効率的に活用できます。
typescript// システムリソースに応じた並列実行数の設定
export default defineConfig({
// CPUコア数に応じた設定
workers: process.env.CI ? 2 : 4,
// メモリ使用量を考慮した設定
use: {
// ブラウザのメモリ制限
args: ['--max-old-space-size=4096'],
},
});
並列実行時のリソース監視:
bash# システムリソースの監視
npx playwright test --workers=4 --reporter=html
# 実行時間の測定
time npx playwright test --reporter=list
テスト分割と分散実行
大規模なテストスイートを効率的に実行するための分割戦略です。
typescript// テスト分割の実装
export default defineConfig({
workers: 1,
projects: [
{
name: 'setup',
testMatch: /.*\.setup\.ts/,
},
{
name: 'smoke',
testMatch: /.*smoke.*\.spec\.ts/,
dependencies: ['setup'],
},
{
name: 'regression',
testMatch: /.*regression.*\.spec\.ts/,
dependencies: ['setup'],
},
],
});
CI/CD 環境での分散実行:
yaml# GitHub Actionsでの分散実行例
name: Playwright Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
shardIndex: [1, 2, 3, 4]
shardTotal: [4]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: yarn install
- name: Install Playwright
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
実行時間の短縮テクニック
テスト実行時間を短縮するための実践的なテクニックを紹介します。
typescript// テストの最適化例
test.describe('最適化されたテスト', () => {
// 共有のセットアップ
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
// 一度だけの初期化処理
});
test.afterAll(async () => {
await page.close();
});
// 軽量なテストケース
test('高速な検証', async () => {
await page.goto('/api/health');
await expect(page).toHaveTitle(/Health/);
});
});
不要な待機時間の削減:
typescript// 効率的な待機処理
test('効率的な要素待機', async ({ page }) => {
await page.goto('/dashboard');
// 明示的な待機ではなく、要素の存在を確認
await expect(
page.locator('[data-testid="user-info"]')
).toBeVisible();
// ネットワークアイドルを待機
await page.waitForLoadState('networkidle');
});
CI/CD 環境での活用
GitHub Actions での設定
GitHub Actions で Playwright テストを効率的に実行する設定例です。
yaml# .github/workflows/playwright.yml
name: Playwright Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
cache: 'yarn'
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test --reporter=html
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
継続的テスト実行
継続的インテグレーションでのテスト実行戦略です。
yaml# 段階的なテスト実行
jobs:
smoke-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
- name: Run smoke tests
run: npx playwright test --grep @smoke
full-tests:
needs: smoke-tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
- name: Run full test suite
run: npx playwright test
失敗時の自動再実行
不安定なテストに対する自動再実行の設定です。
typescript// playwright.config.ts
export default defineConfig({
// 失敗時の再実行設定
retries: process.env.CI ? 2 : 0,
// 特定のテストのみ再実行
projects: [
{
name: 'stable',
retries: 0,
},
{
name: 'flaky',
retries: 3,
testMatch: /.*flaky.*\.spec\.ts/,
},
],
});
再実行の条件設定:
typescript// 条件付き再実行の実装
test.describe('条件付き再実行', () => {
test('不安定なテスト', async ({ page }, testInfo) => {
// テストの実装
// 特定の条件でのみ再実行
if (testInfo.retry > 0) {
// 再実行時の特別な処理
await page.waitForTimeout(2000);
}
});
});
デバッグとトラブルシューティング
テスト実行ログの活用
効果的なデバッグのためのログ活用方法です。
typescript// 詳細なログ出力の設定
export default defineConfig({
// ログレベルの設定
logLevel: 'info',
// トレースの有効化
use: {
trace: 'on-first-retry',
},
// カスタムレポーターの設定
reporter: [
['html'],
['json', { outputFile: 'test-results.json' }],
['junit', { outputFile: 'test-results.xml' }],
],
});
ログ出力の実装例:
typescript// テスト内でのログ出力
test('ログ付きテスト', async ({ page }) => {
console.log('テスト開始');
await page.goto('/login');
console.log('ログインページにアクセス完了');
await page.fill(
'[data-testid="email"]',
'user@example.com'
);
console.log('メールアドレス入力完了');
// エラー時の詳細情報
try {
await page.click('[data-testid="login-button"]');
} catch (error) {
console.error('ログインボタンのクリックに失敗:', error);
await page.screenshot({ path: 'error-screenshot.png' });
throw error;
}
});
失敗原因の特定方法
テスト失敗の原因を効率的に特定する方法です。
typescript// 失敗時の詳細情報収集
test('失敗原因の特定', async ({ page }, testInfo) => {
testInfo.annotations.push({
type: 'test-description',
description: 'ログイン機能のテスト',
});
await page.goto('/login');
// 要素の存在確認
const emailInput = page.locator('[data-testid="email"]');
await expect(emailInput).toBeVisible();
// 失敗時のスクリーンショット
testInfo.attachments.push({
name: 'page-screenshot',
path: await page.screenshot(),
contentType: 'image/png',
});
});
デバッグモードの活用
Playwright のデバッグ機能を活用した効率的な問題解決方法です。
bash# デバッグモードでの実行
npx playwright test --debug
# 特定のテストをデバッグ
npx playwright test login.spec.ts --debug
# ヘッドフルモードでデバッグ
npx playwright test --headed --debug
デバッグ用の設定:
typescript// デバッグ専用の設定
export default defineConfig({
use: {
// デバッグ時の設定
headless: false,
slowMo: 1000,
devtools: true,
// トレースの有効化
trace: 'on',
},
// デバッグ用プロジェクト
projects: [
{
name: 'debug',
use: {
headless: false,
slowMo: 2000,
},
},
],
});
まとめ
Playwright のテストランナーを活用することで、効率的で信頼性の高いテスト実行環境を構築できます。
この記事で紹介した基本機能から高度な最適化テクニックまで、段階的に実装していくことで、テストの実行時間を大幅に短縮し、開発チームの生産性を向上させることができます。
特に重要なポイントは、並列実行の適切な設定、CI/CD 環境での効率的な活用、そして継続的なデバッグとトラブルシューティングです。これらの要素を組み合わせることで、堅牢なテスト自動化システムを構築できます。
実際のプロジェクトでは、チームの規模やプロジェクトの要件に応じて、これらの設定をカスタマイズしていくことが重要です。定期的なパフォーマンス監視と設定の見直しを行い、常に最適な状態を維持することをお勧めします。
関連リンク
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来