SuperAPI AI Directory

playwright

Testing & quality

View repository

Updated 10-15 20:09

About this skill

Playwright E2E Testing Skill

References (Official)

Basic Policy of This Skill

  • Basic policy: Test user-visible behavior. Do not depend on implementation details (class names/ids/DOM structure).
  • Locator: getByRole > getByLabel > getByText > getByTestId > CSS selectors. Prioritize role-based above all.
  • Assertions: Use Web First assertions (with auto-retry). Avoid manual isVisible() checks.
  • Test isolation: Each test is completely independent. Eliminate shared state and test order dependencies.
  • Performance: Global installation recommended. On CI, use Linux + only necessary browsers + sharding.

Philosophy (Decision Rules)

  1. Test from the user's perspective: Write tests the way an end user operates. Do not depend on internal APIs or DOM structure.
  2. Prioritize role-based locators: getByRole('button', { name: '送信' }) is resistant to refactoring. CSS selectors break when the DOM changes.
  3. Trust auto-waiting: Playwright automatically waits for element visibility and enabled state. Explicit sleep や waitForTimeout is unnecessary.
  4. Keep tests independent: Each test runs in its own browser context (cookies/storage). Common setup in beforeEach.
  5. Mock external dependencies: Intercept third-party APIs with the Network API. Do not test links to external sites.
  6. Use Trace Viewer for debugging: Trace has more information than screenshots or videos. On CI, enable with on: 'first-retry' .

Priority Order for Locator Selection

// 1. ロールベース(最優先・推奨)
page.getByRole('button', { name: '送信' })
page.getByRole('textbox', { name: 'メールアドレス' })
page.getByRole('heading', { name: 'ログイン' })

// 2. ラベル/プレースホルダー
page.getByLabel('メールアドレス')
page.getByPlaceholder('example@mail.com')

// 3. テキスト
page.getByText('ログイン')

// 4. テストID(他の方法で特定できない場合)
page.getByTestId('submit-button')

// 5. CSSセレクタ(最終手段)
page.locator('#submit-btn')

How to Write Assertions

// 推奨: Web Firstアサーション(自動リトライ付き)
await expect(page.getByText('ようこそ')).toBeVisible()
await expect(page.getByRole('alert')).toHaveText('保存しました')
await expect(page).toHaveURL('/dashboard')

// 非推奨: 手動チェック(リトライなし)
expect(await page.getByText('ようこそ').isVisible()).toBe(true)

Test Structure Patterns

import { test, expect } from '@playwright/test'

test.describe('ログインフロー', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('/login')
  })

  test('正常系_有効な認証情報でダッシュボードに遷移', async ({ page }) => {
    await page.getByLabel('メールアドレス').fill('user@example.com')
    await page.getByLabel('パスワード').fill('password123')
    await page.getByRole('button', { name: 'ログイン' }).click()
    await expect(page).toHaveURL('/dashboard')
  })

  test('異常系_無効なパスワードでエラー表示', async ({ page }) => {
    await page.getByLabel('メールアドレス').fill('user@example.com')
    await page.getByLabel('パスワード').fill('wrong')
    await page.getByRole('button', { name: 'ログイン' }).click()
    await expect(page.getByRole('alert')).toHaveText('認証に失敗しました')
  })
})

CI Optimization

// playwright.config.ts のCI向け設定
export default defineConfig({
  // CIでは全リトライ1回
  retries: process.env.CI ? 1 : 0,
  // CIでは並列ワーカーを制限
  workers: process.env.CI ? 2 : undefined,
  // Traceは最初のリトライ時のみ
  use: {
    trace: 'on-first-retry',
  },
})
# CIで必要なブラウザだけインストール
npx playwright install --with-deps chromium

# シャーディングで並列化
npx playwright test --shard=1/3
npx playwright test --shard=2/3
npx playwright test --shard=3/3

Output Format (Always in This Order)

  1. Recommended policy (1-3 lines)
  2. Rationale (test stability / maintainability / user perspective)
  3. Design proposal (flow under test / locator strategy / mock strategy / CI configuration)
  4. Checklist (confirm before implementation)
  5. Pitfalls (to avoid)
  6. Next actions (order of small experiments)

Checklist

  • Locators are role-based (getByRole) is given top priority
  • Assertions use Web First (await expect(...).toBeVisible() , etc.)
  • Each test is independent (no shared state or order dependency)
  • waitForTimeout / sleep is not used
  • External APIs/services are mocked with the Network API
  • Trace Viewer is enabled on CI (on-first-retry)
  • Test names express "which flow_under what conditions_what happens"

Common pitfalls

  • CSS selectors (.btn-primary) and refactoring breaks everything
  • page.waitForTimeout(3000) trying to absorb CI environment speed differences (the root cause of flakiness)
  • Sharing login state between tests, causing failures only on CI due to order dependency
  • Writing a large number of E2E tests makes CI execution time tens of minutes, slowing down the development cycle
  • Screenshot comparisons produce false positives due to font rendering differences (threshold settings are required)
  • The Playwright version is old, and tests break due to behavior changes in the latest browsers