T-CREATOR

【2025 年最新】Playwright 入門:E2E テストの基本・特徴・できること完全ガイド

【2025 年最新】Playwright 入門:E2E テストの基本・特徴・できること完全ガイド

2025 年の Web アプリケーション開発において、品質保証は最も重要な要素の一つです。その中でも、エンドツーエンド(E2E)テストは、ユーザー体験を直接検証する強力な手法として注目を集めています。

本記事では、E2E テストの基本概念から、その最新かつ強力なツールである Playwright の特徴、具体的な実装方法まで、初心者の方にもわかりやすく解説いたします。Playwright の魅力を最大限に活用して、効率的で信頼性の高いテストを構築していきましょう。

E2E テストとは何か

E2E テストの概要

End-to-End(E2E)テストとは、アプリケーションを実際のユーザーの行動と同じようにテストする手法です。ユーザーが Web サイトを訪問してから、目的を達成するまでの一連の流れを自動化してテストします。

以下の図で、E2E テストの全体的な流れを確認してみましょう。

mermaidflowchart LR
  user[ユーザー] -->|ブラウザアクセス| web[Webアプリケーション]
  web -->|APIリクエスト| backend[バックエンド]
  backend -->|データアクセス| db[(データベース)]

  e2e[E2Eテスト] -->|同じ操作を自動実行| web
  e2e -->|結果検証| result[テスト結果]

E2E テストは、実際のブラウザを使って Web ページの表示から、ボタンクリック、フォーム入力、画面遷移まで、すべての操作を自動化します。これにより、ユーザーが実際に体験する品質を確実に検証できるのです。

なぜ E2E テストが重要なのか

モダンな Web アプリケーションは、フロントエンド、バックエンド、データベース、外部 API など複数のコンポーネントが連携して動作します。

mermaidflowchart TD
  frontend[フロントエンド<br/>React/Vue/Angular]
  backend[バックエンドAPI<br/>Node.js/Python/Java]
  database[(データベース<br/>MySQL/PostgreSQL)]
  external[外部API<br/>決済/認証サービス]

  frontend <-->|HTTP/REST| backend
  backend <-->|SQL| database
  backend <-->|API Call| external

  style frontend fill:#e1f5fe
  style backend fill:#f3e5f5
  style database fill:#e8f5e8
  style external fill:#fff3e0

各コンポーネントが個別に正常に動作していても、それらが連携した時に問題が発生する可能性があります。E2E テストの重要性は以下の点にあります。

統合的な品質保証

  • フロントエンドとバックエンドの連携確認
  • データの整合性検証
  • 実際のユーザー体験の品質確認

リグレッション(機能の退化)の防止

  • 新機能追加時の既存機能への影響確認
  • デプロイ前の最終品質チェック
  • 継続的な品質維持

開発効率の向上

  • 手動テストの工数削減
  • 早期のバグ発見
  • 開発者の安心感とスピード向上

従来のテスト手法との違い

Web アプリケーションのテストには、いくつかのレベルがあります。それぞれの特徴と役割を理解することで、E2E テストの位置づけが明確になります。

テストレベル対象範囲実行速度メンテナンスカバレッジ
ユニットテスト関数・メソッド単位高速簡単コード詳細
統合テストコンポーネント間中速中程度モジュール連携
E2E テストシステム全体低速複雑ユーザー体験

ユニットテストとの違い

  • ユニットテスト:個別の関数や処理の正確性を検証
  • E2E テスト:システム全体の動作とユーザー体験を検証

統合テストとの違い

  • 統合テスト:複数のモジュール間の連携を検証
  • E2E テスト:実際のブラウザでの操作を含めた総合的な検証
mermaidflowchart TD
  unit[ユニットテスト<br/>個別機能の検証]
  integration[統合テスト<br/>コンポーネント連携]
  e2e[E2Eテスト<br/>ユーザー体験検証]

  unit -->|スコープ拡大| integration
  integration -->|スコープ拡大| e2e

  style unit fill:#ffebee
  style integration fill:#fff3e0
  style e2e fill:#e8f5e8

E2E テストは、他のテスト手法では発見できない実環境特有の問題を検出できる点で、特に価値の高いテスト手法なのです。

Playwright の基本

Playwright とは

Playwright は Microsoft が開発した、モダンな Web アプリケーションのための E2E テストフレームワークです。2020 年にオープンソースとして公開され、急速に開発者コミュニティで支持を集めています。

Playwright の基本的な特徴は以下の通りです。

マルチブラウザ対応

  • Chromium(Chrome、Edge)
  • Firefox
  • WebKit(Safari)

プログラミング言語サポート

  • JavaScript / TypeScript
  • Python
  • Java
  • .NET

自動化機能

  • ページ操作の自動化
  • スクリーンショット撮影
  • 動画録画
  • ネットワーク操作のモニタリング

Playwright のアーキテクチャを以下の図で確認してみましょう。

mermaidflowchart TB
  test[テストコード<br/>JavaScript/TypeScript]
  playwright[Playwright API]

  subgraph browsers [ブラウザエンジン]
    chromium[Chromium<br/>Chrome/Edge]
    firefox[Firefox]
    webkit[WebKit<br/>Safari]
  end

  test -->|API呼び出し| playwright
  playwright -->|制御| chromium
  playwright -->|制御| firefox
  playwright -->|制御| webkit

  style test fill:#e3f2fd
  style playwright fill:#f3e5f5
  style browsers fill:#e8f5e8

Playwright は、単一の API で複数のブラウザを制御でき、クロスブラウザテストを効率的に実装できます。

他のテストツールとの比較

E2E テストツールには複数の選択肢があります。主要なツールと Playwright の比較を見てみましょう。

機能PlaywrightSeleniumCypressPuppeteer
ブラウザサポートChrome/Firefox/Safari全ブラウザChrome/Firefox/EdgeChrome 系のみ
言語サポート4 言語多数言語JavaScriptJavaScript
実行速度高速中速高速高速
並列実行ネイティブ対応可能有料版のみ手動設定
API テスト対応不可対応不可
学習コスト

Selenium との違い

Selenium は歴史が長く安定していますが、設定が複雑で実行速度が遅い傾向があります。

javascript// Selenium WebDriverの例
const { Builder, By } = require('selenium-webdriver');
const driver = new Builder().forBrowser('chrome').build();

await driver.get('https://example.com');
await driver
  .findElement(By.id('username'))
  .sendKeys('user');
await driver
  .findElement(By.id('password'))
  .sendKeys('pass');
await driver
  .findElement(By.css('button[type="submit"]'))
  .click();
javascript// Playwrightの例
const { chromium } = require('playwright');
const browser = await chromium.launch();
const page = await browser.newPage();

await page.goto('https://example.com');
await page.fill('#username', 'user');
await page.fill('#password', 'pass');
await page.click('button[type="submit"]');

Playwright の方がシンプルで直感的な記述が可能です。

Cypress との違い

Cypress は開発者体験に優れていますが、ブラウザサポートが限定的で、真の並列実行には有料版が必要です。

Puppeteer との違い

Puppeteer は Google が開発した Chrome 専用のツールで、軽量ですがブラウザサポートが限定的です。

Playwright の主要な特徴

Playwright の主要な特徴を詳しく見てみましょう。

1. 自動待機機能

従来のテストツールでは、要素の表示を待つためにスリープ処理を記述する必要がありました。Playwright は自動的に要素が操作可能になるまで待機します。

javascript// 従来のツール
await page.waitForSelector('#button');
await page.click('#button');

// Playwright
await page.click('#button'); // 自動的に要素を待機

2. ネットワーク制御

API リクエストの監視やモックが簡単に実装できます。

javascript// APIレスポンスのモック
await page.route('**/api/users', (route) => {
  route.fulfill({
    status: 200,
    body: JSON.stringify([
      { id: 1, name: '田中太郎' },
      { id: 2, name: '佐藤花子' },
    ]),
  });
});

3. マルチコンテキスト

一つのブラウザプロセスで複数の独立したブラウザコンテキストを作成できます。

mermaidflowchart TB
  browser[ブラウザプロセス]

  subgraph contexts [ブラウザコンテキスト]
    context1[コンテキスト1<br/>ユーザーA環境]
    context2[コンテキスト2<br/>ユーザーB環境]
    context3[コンテキスト3<br/>管理者環境]
  end

  browser --> context1
  browser --> context2
  browser --> context3

  context1 --> page1[ページ1-1]
  context1 --> page2[ページ1-2]
  context2 --> page3[ページ2-1]
  context3 --> page4[ページ3-1]

  style browser fill:#e3f2fd
  style contexts fill:#f3e5f5

この機能により、異なるユーザー状態での並列テストが効率的に実行できます。

4. トレース機能

テスト実行の様子を詳細に記録し、失敗時の原因分析を容易にします。

javascript// トレース記録の開始
await context.tracing.start({
  screenshots: true,
  snapshots: true,
});

// テスト実行...

// トレース記録の保存
await context.tracing.stop({ path: 'trace.zip' });

これらの特徴により、Playwright は効率的で信頼性の高い E2E テストを実現できるのです。

Playwright でできること

複数ブラウザ対応

Playwright の最も重要な特徴の一つが、複数のブラウザエンジンに対応していることです。一つのテストコードで、Chrome、Firefox、Safari の動作を検証できます。

サポートブラウザエンジン

mermaidflowchart LR
  playwright[Playwright]

  subgraph browsers [対応ブラウザ]
    chromium[Chromium<br/>Chrome/Edge/Opera]
    firefox[Firefox<br/>Gecko エンジン]
    webkit[WebKit<br/>Safari]
  end

  playwright -->|制御| chromium
  playwright -->|制御| firefox
  playwright -->|制御| webkit

  style playwright fill:#e3f2fd
  style browsers fill:#e8f5e8

クロスブラウザテストの実装

javascript// 複数ブラウザでの同じテストを実行
const { chromium, firefox, webkit } = require('playwright');

const browsers = [
  { name: 'Chromium', browser: chromium },
  { name: 'Firefox', browser: firefox },
  { name: 'WebKit', browser: webkit },
];

for (const { name, browser } of browsers) {
  console.log(`${name}でテスト開始`);

  const browserInstance = await browser.launch();
  const page = await browserInstance.newPage();

  await page.goto('https://example.com');
  // テスト処理...

  await browserInstance.close();
}

設定ファイルでの一括指定

javascript// playwright.config.js
module.exports = {
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] },
    },
  ],
};

この設定により、一回のコマンド実行で全ブラウザでのテストが並行実行されます。

自動化可能な操作

Playwright では、ユーザーがブラウザで行うほぼ全ての操作を自動化できます。

基本的な操作

javascript// ページ遷移とナビゲーション
await page.goto('https://example.com');
await page.goBack(); // ブラウザの戻るボタン
await page.goForward(); // ブラウザの進むボタン
await page.reload(); // ページリロード

// クリック操作
await page.click('#button'); // 左クリック
await page.click('#button', { button: 'right' }); // 右クリック
await page.dblclick('#button'); // ダブルクリック

// 入力操作
await page.fill('#input-text', 'テキスト入力');
await page.selectOption('#select', 'option-value');
await page.check('#checkbox'); // チェックボックス選択
await page.uncheck('#checkbox'); // チェックボックス解除

ファイル操作

javascript// ファイルアップロード
await page.setInputFiles('#file-input', 'path/to/file.pdf');

// 複数ファイルのアップロード
await page.setInputFiles('#multiple-files', [
  'file1.jpg',
  'file2.png',
]);

// ファイルダウンロード
const downloadPromise = page.waitForEvent('download');
await page.click('#download-button');
const download = await downloadPromise;
await download.saveAs('downloaded-file.pdf');

ドラッグ&ドロップ

javascript// 要素間のドラッグ&ドロップ
await page.dragAndDrop('#source', '#target');

// 座標指定でのドラッグ
await page
  .locator('#draggable')
  .dragTo(page.locator('#drop-zone'));

キーボード操作

javascript// 特殊キーの操作
await page.keyboard.press('Enter');
await page.keyboard.press('Tab');
await page.keyboard.press('Escape');

// キーの組み合わせ
await page.keyboard.press('Control+C'); // コピー
await page.keyboard.press('Control+V'); // ペースト

// 文字列の直接入力
await page.keyboard.type('こんにちは世界');

モバイルテスト

Playwright は、実際のモバイルデバイスをエミュレートして、スマートフォンやタブレットでの動作をテストできます。

デバイスエミュレーション

javascriptconst { devices } = require('playwright');

// iPhone 12のエミュレーション
const iPhone12 = devices['iPhone 12'];
const browser = await chromium.launch();
const context = await browser.newContext({
  ...iPhone12,
});

const page = await context.newPage();
await page.goto('https://example.com');

利用可能なデバイスプリセット

javascript// 主要なデバイスプリセット一覧
const mobileDevices = [
  'iPhone 12',
  'iPhone 12 Pro',
  'iPhone 13',
  'Pixel 5',
  'Samsung Galaxy S21',
  'iPad Pro',
  'iPad Mini',
];

// 各デバイスでのテスト実行
for (const deviceName of mobileDevices) {
  const device = devices[deviceName];
  const context = await browser.newContext({ ...device });
  // テスト実行...
}

タッチ操作のテスト

javascript// タップ操作
await page.tap('#mobile-button');

// スワイプ操作
await page.locator('#swipeable').swipe('left');

// ピンチ操作(ズーム)
await page.touchscreen.tap(100, 100);
await page.touchscreen.tap(200, 200);

レスポンシブデザインのテスト

javascript// 画面サイズの動的変更
await page.setViewportSize({ width: 375, height: 667 }); // iPhone SE
// モバイル表示のテスト...

await page.setViewportSize({ width: 768, height: 1024 }); // iPad
// タブレット表示のテスト...

await page.setViewportSize({ width: 1920, height: 1080 }); // Desktop
// デスクトップ表示のテスト...

API テスト

Playwright はブラウザテストだけでなく、API テストも効率的に実行できます。

API リクエストの実行

javascript// GETリクエスト
const response = await request.get('/api/users');
expect(response.status()).toBe(200);

const users = await response.json();
expect(users).toHaveLength(3);
javascript// POSTリクエスト
const response = await request.post('/api/users', {
  data: {
    name: '山田太郎',
    email: 'yamada@example.com',
  },
});

expect(response.status()).toBe(201);
const newUser = await response.json();
expect(newUser.name).toBe('山田太郎');

認証付き API テスト

javascript// 認証トークンの設定
const request = playwright.request.newContext({
  baseURL: 'https://api.example.com',
  extraHTTPHeaders: {
    Authorization: 'Bearer your-token-here',
  },
});

// 認証が必要なAPIのテスト
const response = await request.get(
  '/api/protected-resource'
);
expect(response.status()).toBe(200);

UI テストと API テストの組み合わせ

javascript// APIでデータを準備
await request.post('/api/users', {
  data: {
    name: 'テストユーザー',
    email: 'test@example.com',
  },
});

// UIでデータを確認
await page.goto('/users');
await expect(
  page.locator('text=テストユーザー')
).toBeVisible();

この組み合わせにより、データの準備と UI 確認を効率的に実行できます。

mermaidsequenceDiagram
  participant Test as テストコード
  participant API as Backend API
  participant UI as Web UI
  participant DB as データベース

  Test->>API: テストデータ作成
  API->>DB: データ保存
  DB-->>API: 保存完了
  API-->>Test: 作成完了

  Test->>UI: ページアクセス
  UI->>API: データ取得
  API->>DB: データ読み込み
  DB-->>API: データ返却
  API-->>UI: データ表示
  UI-->>Test: 表示確認

Playwright の導入と基本設定

インストール方法

Playwright の導入は非常に簡単です。プロジェクトの種類に応じて、適切な方法を選択しましょう。

新規プロジェクトでの導入

bash# プロジェクトディレクトリの作成
mkdir my-playwright-project
cd my-playwright-project

# npm初期化
npm init -y

# Playwrightのインストール
npm init playwright@latest

このコマンドにより、Playwright の設定ファイルとサンプルテストが自動生成されます。

既存プロジェクトへの追加

bash# Playwrightのインストール
yarn add -D @playwright/test

# ブラウザのインストール
npx playwright install

TypeScript プロジェクトでの設定

bash# TypeScript関連の依存関係追加
yarn add -D typescript @types/node

# TypeScript設定ファイル生成
npx tsc --init

ブラウザの個別インストール

bash# 特定のブラウザのみインストール
npx playwright install chromium
npx playwright install firefox
npx playwright install webkit

# システム依存関係もインストール
npx playwright install-deps

初期設定

Playwright の初期設定では、以下のファイルが重要な役割を果たします。

基本的なディレクトリ構造

perlmy-playwright-project/
├── playwright.config.js    # Playwright設定ファイル
├── tests/                  # テストファイル格納ディレクトリ
│   ├── example.spec.js
│   └── auth.setup.js
├── test-results/           # テスト結果
├── playwright-report/      # HTMLレポート
└── package.json

package.json のスクリプト設定

json{
  "scripts": {
    "test": "playwright test",
    "test:headed": "playwright test --headed",
    "test:ui": "playwright test --ui",
    "test:debug": "playwright test --debug",
    "report": "playwright show-report"
  },
  "devDependencies": {
    "@playwright/test": "^1.40.0"
  }
}

基本的な設定ファイル

playwright.config.js の基本設定

javascript// playwright.config.js
module.exports = {
  // テストディレクトリ
  testDir: './tests',

  // タイムアウト設定
  timeout: 30000,
  expect: {
    timeout: 5000,
  },

  // 失敗時の設定
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,

  // レポート設定
  reporter: [
    ['html'],
    ['list'],
    ['junit', { outputFile: 'test-results/junit.xml' }],
  ],

  // 全テスト共通の設定
  use: {
    baseURL: 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },

  // ブラウザプロジェクト設定
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] },
    },
  ],

  // 開発サーバー設定
  webServer: {
    command: 'npm run start',
    port: 3000,
    reuseExistingServer: !process.env.CI,
  },
};

環境別設定の管理

javascript// config/playwright.dev.config.js
const baseConfig = require('../playwright.config.js');

module.exports = {
  ...baseConfig,
  use: {
    ...baseConfig.use,
    baseURL: 'http://localhost:3000',
    video: 'on',
    screenshot: 'on',
  },
  workers: 1, // 開発環境では並列度を下げる
};
javascript// config/playwright.prod.config.js
const baseConfig = require('../playwright.config.js');

module.exports = {
  ...baseConfig,
  use: {
    ...baseConfig.use,
    baseURL: 'https://production.example.com',
    video: 'retain-on-failure',
    screenshot: 'only-on-failure',
  },
  retries: 3, // 本番環境では再試行回数を増やす
};

CI/CD 環境での設定

yaml# .github/workflows/playwright.yml
name: Playwright Tests
on:
  push:
    branches: [main, master]
  pull_request:
    branches: [main, master]

jobs:
  test:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 18
      - name: Install dependencies
        run: yarn install --frozen-lockfile
      - name: Install Playwright Browsers
        run: npx playwright install --with-deps
      - name: Run Playwright tests
        run: yarn test
      - uses: actions/upload-artifact@v3
        if: always()
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 30

これらの設定により、開発から CI/CD まで一貫したテスト環境を構築できます。

実際のテストコード例

簡単なページアクセステスト

最初に、基本的なページアクセスとコンテンツ確認のテストから始めましょう。

基本的なページテスト

javascript// tests/basic-page.spec.js
const { test, expect } = require('@playwright/test');

test('ホームページの基本要素を確認', async ({ page }) => {
  // ページにアクセス
  await page.goto('https://example.com');

  // ページタイトルを確認
  await expect(page).toHaveTitle(/Example Domain/);

  // 特定の見出しが表示されているか確認
  await expect(page.locator('h1')).toHaveText(
    'Example Domain'
  );

  // 特定のテキストが含まれているか確認
  await expect(page.locator('body')).toContainText(
    'illustrative examples'
  );

  // リンクが正しく設定されているか確認
  const moreInfoLink = page.locator(
    'a:has-text("More information")'
  );
  await expect(moreInfoLink).toHaveAttribute(
    'href',
    /iana.org/
  );
});

レスポンシブデザインのテスト

javascripttest('レスポンシブ表示の確認', async ({ page }) => {
  await page.goto('https://example.com');

  // デスクトップ表示
  await page.setViewportSize({ width: 1200, height: 800 });
  await expect(page.locator('.desktop-menu')).toBeVisible();

  // タブレット表示
  await page.setViewportSize({ width: 768, height: 1024 });
  await expect(
    page.locator('.tablet-layout')
  ).toBeVisible();

  // モバイル表示
  await page.setViewportSize({ width: 375, height: 667 });
  await expect(
    page.locator('.mobile-menu-button')
  ).toBeVisible();
  await expect(
    page.locator('.desktop-menu')
  ).not.toBeVisible();
});

ページ読み込み速度のテスト

javascripttest('ページ読み込み性能を確認', async ({ page }) => {
  const startTime = Date.now();

  await page.goto('https://example.com');

  // ページの完全読み込みを待機
  await page.waitForLoadState('networkidle');

  const loadTime = Date.now() - startTime;

  // 3秒以内で読み込み完了を期待
  expect(loadTime).toBeLessThan(3000);

  console.log(`ページ読み込み時間: ${loadTime}ms`);
});

フォーム入力テスト

Web アプリケーションで最も重要な機能の一つであるフォーム処理のテストを見てみましょう。

基本的なフォーム入力テスト

javascripttest('ユーザー登録フォームのテスト', async ({ page }) => {
  await page.goto('/register');

  // フォーム要素への入力
  await page.fill('#username', 'testuser123');
  await page.fill('#email', 'test@example.com');
  await page.fill('#password', 'SecurePass123!');
  await page.fill('#confirm-password', 'SecurePass123!');

  // セレクトボックスの選択
  await page.selectOption('#country', 'JP');

  // チェックボックスの選択
  await page.check('#terms-agreement');

  // フォーム送信
  await page.click('#submit-button');

  // 成功メッセージの確認
  await expect(
    page.locator('.success-message')
  ).toContainText('登録が完了しました');

  // リダイレクト先の確認
  await expect(page).toHaveURL(/.*\/welcome/);
});

フォームバリデーションのテスト

javascripttest('フォームバリデーションエラーの確認', async ({
  page,
}) => {
  await page.goto('/register');

  // 無効なメールアドレスでテスト
  await page.fill('#email', 'invalid-email');
  await page.fill('#password', '123'); // 短すぎるパスワード
  await page.click('#submit-button');

  // エラーメッセージの確認
  await expect(page.locator('#email-error')).toContainText(
    '有効なメールアドレスを入力してください'
  );
  await expect(
    page.locator('#password-error')
  ).toContainText(
    'パスワードは8文字以上で入力してください'
  );

  // フォームが送信されていないことを確認
  await expect(page).toHaveURL(/.*\/register/);
});

ファイルアップロードのテスト

javascripttest('プロフィール画像アップロードのテスト', async ({
  page,
}) => {
  await page.goto('/profile/edit');

  // ファイル選択
  const fileInput = page.locator('#profile-image');
  await fileInput.setInputFiles(
    'test-fixtures/sample-image.jpg'
  );

  // プレビュー表示の確認
  await expect(
    page.locator('#image-preview')
  ).toBeVisible();

  // アップロード実行
  await page.click('#upload-button');

  // アップロード完了の確認
  await expect(
    page.locator('.upload-success')
  ).toContainText('画像をアップロードしました');

  // 画像が表示されていることを確認
  const uploadedImage = page.locator(
    '#current-profile-image'
  );
  await expect(uploadedImage).toHaveAttribute(
    'src',
    /.*\.jpg$/
  );
});

ナビゲーションテスト

Web サイト内の移動やナビゲーション機能のテストを実装します。

メニューナビゲーションのテスト

javascripttest('メインナビゲーションの動作確認', async ({ page }) => {
  await page.goto('/');

  // ヘッダーメニューの確認
  const navigation = page.locator('nav.main-navigation');
  await expect(navigation).toBeVisible();

  // 各メニューリンクをテスト
  const menuItems = [
    { text: 'ホーム', url: '/' },
    { text: '製品', url: '/products' },
    { text: '会社概要', url: '/about' },
    { text: 'お問い合わせ', url: '/contact' },
  ];

  for (const item of menuItems) {
    await page.click(`nav a:has-text("${item.text}")`);
    await expect(page).toHaveURL(new RegExp(item.url));

    // ページが正しく読み込まれたことを確認
    await page.waitForLoadState('networkidle');

    // アクティブメニューの表示確認
    await expect(
      page.locator(`nav a:has-text("${item.text}")`)
    ).toHaveClass(/active/);
  }
});

パンくずナビゲーションのテスト

javascripttest('パンくずナビゲーションの確認', async ({ page }) => {
  // 深い階層のページに移動
  await page.goto(
    '/products/electronics/smartphones/iphone'
  );

  // パンくずリストの確認
  const breadcrumb = page.locator('.breadcrumb');
  await expect(breadcrumb).toBeVisible();

  // パンくずの各階層を確認
  await expect(
    breadcrumb.locator('a:has-text("ホーム")')
  ).toBeVisible();
  await expect(
    breadcrumb.locator('a:has-text("製品")')
  ).toBeVisible();
  await expect(
    breadcrumb.locator('a:has-text("電子機器")')
  ).toBeVisible();
  await expect(
    breadcrumb.locator('a:has-text("スマートフォン")')
  ).toBeVisible();
  await expect(
    breadcrumb.locator('span:has-text("iPhone")')
  ).toBeVisible();

  // パンくずリンクの動作確認
  await page.click('.breadcrumb a:has-text("製品")');
  await expect(page).toHaveURL(/.*\/products$/);
});

検索機能のテスト

javascripttest('サイト内検索機能のテスト', async ({ page }) => {
  await page.goto('/');

  // 検索ボックスの表示確認
  const searchBox = page.locator('#search-input');
  await expect(searchBox).toBeVisible();

  // 検索実行
  await searchBox.fill('Playwright');
  await page.click('#search-button');

  // 検索結果ページの確認
  await expect(page).toHaveURL(/.*\/search/);
  await expect(
    page.locator('.search-results')
  ).toBeVisible();

  // 検索結果の内容確認
  const results = page.locator('.search-result-item');
  await expect(results.first()).toContainText('Playwright');

  // 結果数の表示確認
  await expect(
    page.locator('.results-count')
  ).toContainText(/\d+件の結果/);
});

以下の図で、これらのテストがカバーする範囲を確認してみましょう。

mermaidflowchart TD
  user[ユーザー] -->|ページアクセス| page[ページ表示テスト]
  user -->|フォーム入力| form[フォームテスト]
  user -->|サイト内移動| nav[ナビゲーションテスト]

  page -->|確認項目| page_items[タイトル<br/>コンテンツ<br/>レスポンシブ<br/>読み込み速度]

  form -->|確認項目| form_items[入力処理<br/>バリデーション<br/>ファイルアップロード<br/>送信結果]

  nav -->|確認項目| nav_items[メニュー操作<br/>パンくず<br/>検索機能<br/>URL遷移]

  style user fill:#e3f2fd
  style page fill:#e8f5e8
  style form fill:#fff3e0
  style nav fill:#f3e5f5

これらのテストパターンを組み合わせることで、ユーザーの主要な操作を網羅的に検証できます。

まとめ

本記事では、E2E テストの基本概念から、Playwright の特徴、具体的な実装方法まで、初心者の方にもわかりやすく解説してまいりました。

E2E テストの重要なポイント

  • システム全体の動作をユーザー視点で検証
  • 手動テストでは発見困難な問題の検出
  • 継続的な品質保証の実現

Playwright の優位性

  • マルチブラウザ対応による幅広い検証範囲
  • 自動待機機能による安定したテスト実行
  • 豊富な機能によるあらゆる操作の自動化
  • 優れた開発者体験とデバッグ機能

実装における重要な考慮点

  • 適切な設定ファイルの管理
  • 環境別の設定分離
  • 効率的なテストケース設計
  • メンテナンス性を意識したコード構造

2025 年の Web アプリケーション開発において、Playwright を活用した E2E テストは、品質の高いサービスを提供するための必須要素となっています。本記事で学んだ知識を活用して、信頼性の高いテスト環境を構築し、より良いユーザー体験の提供を実現してください。

テスト自動化の journey は一歩ずつの積み重ねです。まずは簡単なページアクセステストから始めて、徐々に複雑な機能のテストに挑戦していきましょう。きっと、開発効率とプロダクト品質の向上を実感していただけるはずです。

関連リンク