Playwright入門:TypeScriptでE2Eテストを書く

スポンサーリンク

Playwright入門:TypeScriptでE2Eテストを書く

Playwrightとは

PlaywrightはMicrosoftが開発するE2E(End-to-End)テストフレームワークです。実際のブラウザを操作してユーザーの操作を自動化し、アプリ全体の動作を確認できます。

  • Chromium・Firefox・WebKit(Safari)の3ブラウザに対応
  • TypeScriptファーストで型補完が効く
  • ロケーターAPIが直感的で保守しやすい
  • UIモードで視覚的にテストを確認できる

セットアップ

新規プロジェクトに追加する

npm init playwright@latest

対話形式でセットアップされます。tests/ ディレクトリが作成され、playwright.config.ts が生成されます。

既存プロジェクトに追加する

npm install -D @playwright/test
npx playwright install  # ブラウザのインストール

基本的なテストの書き方

// tests/example.spec.ts
import { test, expect } from '@playwright/test'

test('ページタイトルを確認する', async ({ page }) => {
  await page.goto('https://example.com')
  await expect(page).toHaveTitle(/Example Domain/)
})

test('リンクをクリックしてページ遷移する', async ({ page }) => {
  await page.goto('https://example.com')
  await page.getByRole('link', { name: 'More information' }).click()
  await expect(page).toHaveURL(/iana.org/)
})

test() の第2引数の { page } はPlaywrightが提供するフィクスチャで、ブラウザのページを表します。


ロケーター(要素の取得)

Playwrightはユーザー視点で要素を取得するロケーターAPIを推奨しています。

// ロールで取得(最推奨)
page.getByRole('button', { name: '送信' })
page.getByRole('link', { name: 'トップへ' })
page.getByRole('textbox', { name: 'メールアドレス' })

// ラベルで取得
page.getByLabel('パスワード')

// プレースホルダーで取得
page.getByPlaceholder('example@email.com')

// テキストで取得
page.getByText('ようこそ')

// テストIDで取得(data-testid属性)
page.getByTestId('submit-button')

// CSSセレクター(最終手段)
page.locator('.submit-btn')
page.locator('#email')
ロケーター 使いどころ
getByRole ボタン・リンク・入力欄など意味のある要素
getByLabel フォームの入力欄(label と紐づいているもの)
getByText 特定のテキストを含む要素
getByTestId テスト専用属性で確実に特定したい場合
locator CSSセレクターで直接指定する場合

ページ操作

test('フォームの入力と送信', async ({ page }) => {
  await page.goto('/login')

  // テキスト入力
  await page.getByLabel('メールアドレス').fill('user@example.com')
  await page.getByLabel('パスワード').fill('password123')

  // クリック
  await page.getByRole('button', { name: 'ログイン' }).click()

  // ドロップダウンの選択
  await page.getByLabel('言語').selectOption('ja')

  // チェックボックス
  await page.getByLabel('利用規約に同意する').check()

  // キーボード操作
  await page.getByRole('textbox').press('Enter')
})

アサーション

// ページ全体
await expect(page).toHaveTitle('ダッシュボード')
await expect(page).toHaveURL('/dashboard')

// 要素の状態
await expect(page.getByText('ようこそ')).toBeVisible()
await expect(page.getByRole('button', { name: '削除' })).toBeEnabled()
await expect(page.getByRole('checkbox')).toBeChecked()
await expect(page.getByRole('button', { name: '送信' })).toBeDisabled()

// テキスト・値
await expect(page.getByRole('heading')).toHaveText('マイページ')
await expect(page.getByLabel('名前')).toHaveValue('田中太郎')

// 件数
await expect(page.getByRole('listitem')).toHaveCount(5)

実践例:ログインフローのテスト

// tests/login.spec.ts
import { test, expect } from '@playwright/test'

test.describe('ログイン', () => {
  test('正しい認証情報でログインできる', async ({ page }) => {
    await page.goto('/login')

    await page.getByLabel('メールアドレス').fill('user@example.com')
    await page.getByLabel('パスワード').fill('password123')
    await page.getByRole('button', { name: 'ログイン' }).click()

    await expect(page).toHaveURL('/dashboard')
    await expect(page.getByText('ようこそ、田中さん')).toBeVisible()
  })

  test('誤ったパスワードでエラーが表示される', async ({ page }) => {
    await page.goto('/login')

    await page.getByLabel('メールアドレス').fill('user@example.com')
    await page.getByLabel('パスワード').fill('wrong-password')
    await page.getByRole('button', { name: 'ログイン' }).click()

    await expect(page.getByText('メールアドレスまたはパスワードが正しくありません')).toBeVisible()
    await expect(page).toHaveURL('/login')
  })
})

playwright.config.ts の基本設定

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

export default defineConfig({
  testDir: './tests',
  use: {
    baseURL: 'http://localhost:3000',  // page.goto('/login') のベースURL
    screenshot: 'only-on-failure',     // 失敗時にスクリーンショットを保存
    video: 'retain-on-failure',        // 失敗時に動画を保存
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
  ],
})

baseURL を設定すると page.goto('/login') のように相対パスで書けます。


テストの実行

# 全テストを実行
npx playwright test

# 特定のファイルだけ実行
npx playwright test tests/login.spec.ts

# ブラウザを表示して実行(デバッグ時)
npx playwright test --headed

# UIモードで実行(視覚的に確認できる)
npx playwright test --ui

# レポートを表示
npx playwright show-report

まとめ

操作 メソッド
ページ遷移 page.goto(url)
テキスト入力 locator.fill(text)
クリック locator.click()
選択 locator.selectOption(value)
チェック locator.check()
アサーション 確認内容
toHaveTitle() ページタイトル
toHaveURL() URL
toBeVisible() 表示されているか
toHaveText() テキスト内容
toBeEnabled() / toBeDisabled() 有効・無効状態
toHaveCount() 要素の件数
  • getByRole / getByLabel など意味のあるロケーターを使うと、実装の変更に強いテストになる
  • baseURL を設定すると相対パスで書けてテスト環境の切り替えが楽になる
  • --ui モードを使うとテストの実行過程を視覚的に確認・デバッグできる

コンポーネント単位の動作確認には「Storybook入門:React TypeScriptでコンポーネントのStoryを書く」も参照してください。