Skip to content

Playwrightの構文

Playwrightのテストは、@playwright/testという組み込みのテストランナーを使用して記述します。これにより、テストの構造化とアサーションが簡単になります。

テストは**test関数で定義し、検証にはexpect関数**を使用します。pageオブジェクトは、ブラウザ操作(ページの移動、クリック、入力など)を行うための中心的な役割を果たします。

const { test, expect } = require('@playwright/test');
test('基本テスト:ページのタイトルを検証', async ({ page }) => {
await page.goto('https://example.com');
// ページのタイトルを検証します
await expect(page).toHaveTitle(/Example Domain/);
});

expect(page).toHaveTitle()のように、アサーションは非常に読みやすく設計されています。

Playwrightは、複雑なユーザーインタラクションを簡単に再現できます。

page.click(), page.fill(), page.press()といったメソッドを使用して、クリック、テキスト入力、キーボード操作をシミュレートします。

test('複雑なユーザーインタラクション', async ({ page }) => {
await page.goto('https://playwright.dev/login');
// フォームにユーザー名とパスワードを入力
await page.fill('#username', 'testuser');
await page.fill('#password', 'password123');
// ログインボタンをクリック
await page.click('#login-button');
// ログイン後のウェルカムメッセージを検証
const welcomeMessage = await page.locator('#welcome-message');
await expect(welcomeMessage).toHaveText('Welcome, testuser!');
});

Playwrightは、GitHub ActionsなどのCI/CDプラットフォームに簡単に統合できます。CI/CDパイプラインにテストを組み込むことで、コードが変更されるたびに自動でテストが実行され、デプロイ前にバグを発見できます。

.github/workflows/playwright.ymlファイルを作成し、以下の内容を記述します。

name: Playwright Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm install
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30

このワークフローは、pushまたはpull_requestが発生するたびに自動でテストを実行し、テスト結果のレポートをアップロードします。

デバッグとトラブルシューティング 🐞

Section titled “デバッグとトラブルシューティング 🐞”

Playwrightには、テストのデバッグを助ける強力なツールが組み込まれています。

npx playwright test --uiコマンドを実行すると、GUIでテストをステップ実行したり、DOMスナップショットを確認したりできます。

page.pause()をテストコードに挿入することで、特定の場所でテスト実行を一時停止し、ブラウザ上で要素の状態などを手動で確認できます。

test('デバッグテスト', async ({ page }) => {
await page.goto('https://example.com');
await page.pause(); // ここでテストが一時停止
// 手動で操作を確認後、ターミナルでresume
});

テストの実行時間を短縮し、効率を向上させるための手法です。

Playwrightはデフォルトで並列実行をサポートしています。設定ファイルplaywright.config.jsworkersの数を調整できます。

playwright.config.js
module.exports = {
// 並列実行するworkerの数を指定
workers: process.env.CI ? 2 : undefined,
};

CI環境ではworkersの数を明示的に指定することで、CIサーバーのリソースを最大限に活用できます。

各テストケースは独立して実行されるように設計します。これにより、並列実行の効果が最大化されます。

Playwrightは、Webアプリケーションのセキュリティテストにも利用できます。

認証APIが正しく動作するか、不正な認証情報が拒否されるかをテストします。

test('不正なログイン', async ({ page }) => {
await page.goto('https://playwright.dev/login');
await page.getByLabel('Username').fill('invalid-user');
await page.getByLabel('Password').fill('wrong-password');
await page.getByRole('button', { name: 'Log in' }).click();
// エラーメッセージが表示されることを検証
const errorMessage = page.getByText('Invalid credentials');
await expect(errorMessage).toBeVisible();
});

page.route()メソッドを使って、特定のリクエストをインターセプトし、レスポンスを検証することも可能です。これにより、アプリケーションが機密データを正しく扱っているかをテストできます。

test('APIリクエストの検証', async ({ page }) => {
let interceptedRequest = null;
await page.route('**/api/login', route => {
interceptedRequest = route.request();
route.continue();
});
await page.goto('https://example.com/login');
await page.getByLabel('Username').fill('testuser');
await page.getByLabel('Password').fill('password123');
await page.getByRole('button', { name: 'Log in' }).click();
// リクエストが正しく送信されたか検証
expect(interceptedRequest.postData()).toContain('testuser');
});

test.describe()でテストをグループ化

Section titled “test.describe()でテストをグループ化”
import { test, expect } from '@playwright/test';
test.describe('ログイン機能', () => {
test('正常なログイン', async ({ page }) => {
await page.goto('https://example.com/login');
await page.getByLabel('Username').fill('validuser');
await page.getByLabel('Password').fill('validpassword');
await page.getByRole('button', { name: 'Log in' }).click();
await expect(page).toHaveURL(/dashboard/);
});
test('不正な認証情報でのログイン', async ({ page }) => {
await page.goto('https://example.com/login');
await page.getByLabel('Username').fill('invaliduser');
await page.getByLabel('Password').fill('wrongpassword');
await page.getByRole('button', { name: 'Log in' }).click();
await expect(page.getByText('Invalid credentials')).toBeVisible();
});
});
test.describe('ユーザー管理', () => {
test.beforeEach(async ({ page }) => {
// 各テストの前に実行
await page.goto('https://example.com');
await page.getByRole('button', { name: 'Log in' }).click();
await page.getByLabel('Username').fill('admin');
await page.getByLabel('Password').fill('admin123');
await page.getByRole('button', { name: 'Log in' }).click();
});
test.afterEach(async ({ page }) => {
// 各テストの後に実行
await page.getByRole('button', { name: 'Log out' }).click();
});
test('ユーザー一覧の表示', async ({ page }) => {
await page.getByRole('link', { name: 'Users' }).click();
await expect(page.getByText('User List')).toBeVisible();
});
});

パターン1: フォーム送信のテスト

Section titled “パターン1: フォーム送信のテスト”
test('フォーム送信のテスト', async ({ page }) => {
await page.goto('https://example.com/contact');
// フォームに入力
await page.getByLabel('Name').fill('John Doe');
await page.getByLabel('Email').fill('john@example.com');
await page.getByLabel('Message').fill('Hello, this is a test message.');
// 送信
await page.getByRole('button', { name: 'Submit' }).click();
// 成功メッセージの確認
await expect(page.getByText('Thank you for your message')).toBeVisible();
});
test('検索機能のテスト', async ({ page }) => {
await page.goto('https://example.com');
// 検索ボックスに入力
await page.getByPlaceholder('Search...').fill('Playwright');
await page.getByRole('button', { name: 'Search' }).click();
// 検索結果の確認
await expect(page.getByText('Search results')).toBeVisible();
await expect(page.getByText('Playwright')).toBeVisible();
});

パターン3: モーダルダイアログのテスト

Section titled “パターン3: モーダルダイアログのテスト”
test('モーダルダイアログのテスト', async ({ page }) => {
await page.goto('https://example.com');
// モーダルを開く
await page.getByRole('button', { name: 'Open modal' }).click();
// モーダルが表示されることを確認
const modal = page.getByRole('dialog');
await expect(modal).toBeVisible();
// モーダル内の操作
await modal.getByLabel('Input').fill('Test value');
await modal.getByRole('button', { name: 'Save' }).click();
// モーダルが閉じることを確認
await expect(modal).toBeHidden();
});