10日で覚えるPlaywrightDay 10: CI/CDとベストプラクティス
books.chapter 1010日で覚えるPlaywright

Day 10: CI/CDとベストプラクティス

今日学ぶこと

  • CI/CDでPlaywrightを実行する理由
  • GitHub Actionsでのセットアップ
  • テストアーティファクト(レポート、スクリーンショット、動画、トレース)
  • DockerでのPlaywright実行
  • 認証状態の再利用(storageState)
  • テスト設計のベストプラクティス
  • フレイキーテストへの対処
  • テスト戦略:E2E vs ユニット/インテグレーション
  • 10日間の振り返り

なぜCI/CDでPlaywrightを実行するのか

ローカルでの手動テスト実行だけでは、品質を継続的に保つことは困難です。

flowchart LR
    subgraph Manual["手動テスト"]
        M1["忘れがち"]
        M2["環境差異"]
        M3["時間がかかる"]
    end

    subgraph CICD["CI/CD自動テスト"]
        C1["毎回自動実行"]
        C2["統一環境"]
        C3["高速フィードバック"]
    end

    style Manual fill:#ef4444,color:#fff
    style CICD fill:#22c55e,color:#fff

CI/CDパイプラインにPlaywrightを組み込むことで、コードの変更が既存機能を壊していないことを自動的に確認できます。


GitHub Actionsでのセットアップ

基本的なワークフロー

# .github/workflows/playwright.yml
name: Playwright Tests

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright browsers
        run: npx playwright install --with-deps

      - name: Run Playwright tests
        run: npx playwright test

      - name: Upload HTML report
        uses: actions/upload-artifact@v4
        if: ${{ !cancelled() }}
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 30

ワークフローの流れ

flowchart TB
    subgraph CI["GitHub Actions ワークフロー"]
        A["コードをチェックアウト"] --> B["Node.jsセットアップ"]
        B --> C["依存関係インストール"]
        C --> D["ブラウザインストール"]
        D --> E["テスト実行(ヘッドレス)"]
        E --> F{"成功?"}
        F -->|"Yes"| G["完了"]
        F -->|"No"| H["レポート・トレース保存"]
        H --> I["失敗を報告"]
    end

    style CI fill:#8b5cf6,color:#fff
    style G fill:#22c55e,color:#fff
    style I fill:#ef4444,color:#fff

ブラウザキャッシュの活用

ブラウザのインストールは時間がかかるため、キャッシュを使うと高速化できます。

      - name: Cache Playwright browsers
        uses: actions/cache@v4
        id: playwright-cache
        with:
          path: ~/.cache/ms-playwright
          key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}

      - name: Install Playwright browsers
        if: steps.playwright-cache.outputs.cache-hit != 'true'
        run: npx playwright install --with-deps

      - name: Install system dependencies
        if: steps.playwright-cache.outputs.cache-hit == 'true'
        run: npx playwright install-deps

テストアーティファクト

CI環境でテストが失敗したとき、原因を調査するためにアーティファクトが不可欠です。

playwright.config.ts での設定

import { defineConfig } from '@playwright/test';

export default defineConfig({
  reporter: [
    ['html', { open: 'never' }],
    ['junit', { outputFile: 'results.xml' }],
  ],
  use: {
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
    trace: 'retain-on-failure',
  },
});

アーティファクトの種類

アーティファクト 設定値 用途
HTMLレポート reporter: 'html' テスト結果の可視化
スクリーンショット screenshot: 'only-on-failure' 失敗時の画面キャプチャ
動画 video: 'retain-on-failure' 失敗時のテスト再生
トレース trace: 'retain-on-failure' 詳細なデバッグ情報
JUnitレポート reporter: 'junit' CI/CDツールとの連携

GitHub Actionsでのアップロード

      - name: Upload test results
        uses: actions/upload-artifact@v4
        if: ${{ !cancelled() }}
        with:
          name: playwright-report
          path: |
            playwright-report/
            test-results/
          retention-days: 30

test-results/ ディレクトリにはスクリーンショット、動画、トレースファイルが保存されます。


DockerでのPlaywright実行

Playwrightは公式のDockerイメージを提供しています。

公式イメージの使用

FROM mcr.microsoft.com/playwright:v1.50.0-noble

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .

CMD ["npx", "playwright", "test"]

GitHub Actionsでの使用

jobs:
  test:
    runs-on: ubuntu-latest
    container:
      image: mcr.microsoft.com/playwright:v1.50.0-noble

    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npx playwright test
        env:
          HOME: /root

コンテナイメージを使うと、ブラウザのインストール手順が不要になり、環境の一貫性も保証されます。


認証状態の再利用(storageState)

多くのテストでログインが必要な場合、毎回UIでログインするのは非効率です。Playwrightの storageState を使って認証状態を保存・再利用できます。

セットアッププロジェクトの定義

// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  projects: [
    {
      name: 'setup',
      testMatch: /.*\.setup\.ts/,
    },
    {
      name: 'chromium',
      use: {
        storageState: 'playwright/.auth/user.json',
      },
      dependencies: ['setup'],
    },
  ],
});

認証セットアップファイル

// tests/auth.setup.ts
import { test as setup, expect } from '@playwright/test';

const authFile = 'playwright/.auth/user.json';

setup('authenticate', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill('test@example.com');
  await page.getByLabel('Password').fill('password');
  await page.getByRole('button', { name: 'Sign in' }).click();

  await page.waitForURL('/dashboard');
  await expect(page.getByText('Welcome')).toBeVisible();

  // Save authentication state
  await page.context().storageState({ path: authFile });
});
flowchart TB
    subgraph Auth["認証状態の再利用"]
        A["setup プロジェクト"] --> B["ログイン実行"]
        B --> C["storageState を保存"]
        C --> D["chromium プロジェクト"]
        D --> E["保存された状態を読み込み"]
        E --> F["ログイン済みの状態でテスト"]
    end

    style Auth fill:#3b82f6,color:#fff

この方法により、テストごとにログインする必要がなくなり、テスト全体の実行時間を大幅に短縮できます。


テスト設計のベストプラクティス

プロジェクト構成

project-root/
├── tests/
│   ├── auth.setup.ts          # 認証セットアップ
│   ├── auth/
│   │   ├── login.spec.ts
│   │   └── register.spec.ts
│   ├── dashboard/
│   │   ├── overview.spec.ts
│   │   └── settings.spec.ts
│   └── products/
│       ├── list.spec.ts
│       └── detail.spec.ts
├── pages/                      # Page Object Model
│   ├── LoginPage.ts
│   ├── DashboardPage.ts
│   └── ProductPage.ts
├── fixtures/                   # テストデータ
│   └── test-data.json
├── playwright.config.ts
└── package.json

メンテナブルなテストを書くコツ

// NG: 壊れやすいセレクタ
await page.locator('.btn-primary.mt-4.px-6').click();
await page.locator('#root > div > div:nth-child(3) > button').click();

// OK: ロールベースのロケータ
await page.getByRole('button', { name: 'Submit' }).click();
await page.getByLabel('Email').fill('test@example.com');
await page.getByTestId('checkout-button').click();

ロケータの優先順位

優先度 ロケータ 理由
1 getByRole() アクセシビリティに基づく、最も安定
2 getByLabel() フォーム要素に最適
3 getByText() 表示テキストで特定
4 getByTestId() テスト専用属性
5 locator('.class') 最後の手段

テストの独立性

// NG: テスト間に依存関係がある
test('create item', async ({ page }) => {
  // ...create item...
});

test('edit item', async ({ page }) => {
  // create item のテストが先に実行される前提
});

// OK: 各テストが独立している
test('edit item', async ({ page }) => {
  // API経由でデータを準備
  const item = await createTestItem(page);
  await page.goto(`/items/${item.id}/edit`);
  // ...
});

フレイキーテストへの対処

フレイキーテスト(Flaky Test)は、同じコードでも成功したり失敗したりする不安定なテストです。

flowchart TB
    subgraph Causes["フレイキーの原因"]
        C1["タイミング依存"]
        C2["テスト間の状態共有"]
        C3["外部サービス依存"]
        C4["アニメーション"]
        C5["動的コンテンツ"]
    end

    subgraph Solutions["対策"]
        S1["auto-waiting を信頼"]
        S2["テストの独立性確保"]
        S3["APIモック"]
        S4["アニメーション無効化"]
        S5["明示的な待機"]
    end

    C1 --> S1
    C2 --> S2
    C3 --> S3
    C4 --> S4
    C5 --> S5

    style Causes fill:#ef4444,color:#fff
    style Solutions fill:#22c55e,color:#fff

リトライの設定

// playwright.config.ts
export default defineConfig({
  retries: process.env.CI ? 2 : 0,  // CIでは2回リトライ
});

フレイキーテストの検出

# 同じテストを10回繰り返して安定性を確認
npx playwright test --repeat-each=10 tests/checkout.spec.ts

対処のチェックリスト

チェック項目 確認内容
固定の waitForTimeout() auto-waitingで代替できないか
テスト順序依存 単独で実行しても成功するか
外部API依存 route.fulfill() でモックしているか
日付/時刻依存 page.clock を使っているか
ランダムデータ 固定のテストデータを使っているか

テスト戦略:何をE2Eでテストするか

すべてをE2Eテストでカバーする必要はありません。テストピラミッドを意識しましょう。

flowchart TB
    subgraph Pyramid["テストピラミッド"]
        E2E["E2Eテスト<br/>少数・重要フロー"]
        INT["インテグレーションテスト<br/>コンポーネント連携"]
        UNIT["ユニットテスト<br/>多数・高速"]
    end

    E2E --> INT --> UNIT

    style E2E fill:#ef4444,color:#fff
    style INT fill:#f59e0b,color:#000
    style UNIT fill:#22c55e,color:#fff

テスト種別の使い分け

テスト種別 対象
ユニットテスト 個別の関数・クラス バリデーションロジック、計算処理
インテグレーション コンポーネントの連携 APIとDBの連携、UIコンポーネント
E2Eテスト ユーザーフロー全体 ログイン→商品購入→決済

E2Eテストで重点を置くべきシナリオ

  1. クリティカルパス: ログイン、決済、登録など
  2. クロスブラウザの検証: レイアウト崩れ、互換性
  3. ユーザージャーニー: 一連の操作フロー
  4. リグレッション防止: 過去に発生したバグの再発防止

10日間のまとめ

flowchart TB
    subgraph Journey["10日間の学習の道のり"]
        D1["Day 1<br/>Playwrightとは"]
        D2["Day 2<br/>セットアップ"]
        D3["Day 3<br/>ロケータ"]
        D4["Day 4<br/>アサーション"]
        D5["Day 5<br/>ページ操作"]
        D6["Day 6<br/>ネットワーク"]
        D7["Day 7<br/>Page Object"]
        D8["Day 8<br/>フィクスチャ"]
        D9["Day 9<br/>デバッグ"]
        D10["Day 10<br/>CI/CD"]

        D1 --> D2 --> D3 --> D4 --> D5
        D5 --> D6 --> D7 --> D8 --> D9 --> D10
    end

    style D1 fill:#3b82f6,color:#fff
    style D2 fill:#3b82f6,color:#fff
    style D3 fill:#8b5cf6,color:#fff
    style D4 fill:#8b5cf6,color:#fff
    style D5 fill:#8b5cf6,color:#fff
    style D6 fill:#f59e0b,color:#000
    style D7 fill:#f59e0b,color:#000
    style D8 fill:#f59e0b,color:#000
    style D9 fill:#22c55e,color:#fff
    style D10 fill:#22c55e,color:#fff
Day テーマ 学んだこと
1 Playwrightとは E2Eテストの概要、Playwrightの特徴とアーキテクチャ
2 セットアップ インストール、設定、最初のテスト作成
3 ロケータとDOM操作 getByRole, getByText, locator の使い分け
4 アサーション expect, toBeVisible, toHaveText の活用
5 ページ操作とナビゲーション フォーム操作、ファイルアップロード、ダイアログ
6 ネットワーク制御 route.fulfill, waitForResponse, APIモック
7 Page Object Model 再利用可能なページクラスの設計
8 フィクスチャとデータ管理 カスタムフィクスチャ、テストデータの管理
9 デバッグとトレース Trace Viewer, UI Mode, デバッグ手法
10 CI/CDとベストプラクティス GitHub Actions、Docker、テスト戦略

まとめ

概念 説明
GitHub Actions CI/CDでのテスト自動実行
ブラウザキャッシュ CI実行時間の短縮
アーティファクト レポート、スクリーンショット、動画、トレース
Docker 公式イメージによる環境統一
storageState 認証状態の保存と再利用
リトライ CIでのフレイキーテスト対策
テストピラミッド E2E/インテグレーション/ユニットの使い分け

重要ポイント

  1. CI/CDでテストを自動化して品質を守る
  2. storageStateで認証処理を効率化する
  3. フレイキーテストは放置せず根本原因を解決する
  4. テストピラミッドを意識してE2Eテストの範囲を適切に保つ
  5. ロールベースのロケータで壊れにくいテストを書く

練習問題

基本

  1. GitHub Actionsのワークフローファイルを作成し、プッシュ時にPlaywrightテストが自動実行されるようにしてください。
  2. playwright.config.ts でスクリーンショット、動画、トレースの設定を行ってください。
  3. HTMLレポートをアーティファクトとしてアップロードする設定を追加してください。

応用

  1. storageState を使った認証セットアッププロジェクトを作成し、テスト実行時間を短縮してください。
  2. Dockerの公式イメージを使ってPlaywrightテストを実行してください。
  3. --repeat-each=10 を使って、既存テストのフレイキーさを確認してください。

チャレンジ

  1. 複数ブラウザ(Chromium, Firefox, WebKit)でテストを並列実行するGitHub Actionsワークフローを設計してください。失敗時にトレースファイルをアップロードする設定も含めてください。

参考リンク


おめでとうございます!

10日間のPlaywright学習が完了しました!

学んだこと

  1. Day 1: Playwrightとは何か、E2Eテストの重要性
  2. Day 2: 環境構築と最初のテスト
  3. Day 3: ロケータによるDOM操作
  4. Day 4: アサーションでテストを検証
  5. Day 5: ページ操作とナビゲーション
  6. Day 6: ネットワークリクエストの制御
  7. Day 7: Page Object Modelで再利用性向上
  8. Day 8: フィクスチャとテストデータ管理
  9. Day 9: デバッグ手法とトレース
  10. Day 10: CI/CDとベストプラクティス

これからの道

あなたはもうPlaywrightの基礎をしっかりと身につけました。ここからは実際のプロジェクトでテストを書き、経験を積んでいくことが最も大切です。

Playwrightは活発に開発が続けられているツールです。新しいバージョンがリリースされるたびに便利な機能が追加されています。公式ドキュメントを定期的にチェックし、最新の機能やベストプラクティスを取り入れていきましょう。

テストを書くことは、ソフトウェアの品質を守るだけでなく、自信を持ってコードを変更し、素早くリリースすることを可能にします。今日学んだCI/CDの知識を活かして、チームの開発フローにPlaywrightを組み込んでいきましょう。

テストの旅はここから始まります。学び続けて、信頼性の高いWebアプリケーションを作りましょう!