メインコンテンツへスキップ
SDETRole
SDETRole

学ぶ / チートシート

Playwright チートシート

毎日使う Playwright Test の API を 1 枚にまとめました。ロケーターは Playwright が推奨する順に並べています。ロール、ラベル、テキストをテスト ID より優先し、CSS や XPath は最後の手段です。ここに載せたアサーションはすべて Web ファーストで、合格するかタイムアウトするまで自動で再試行するため、手動の待機は不要です。

Playwright Test 1.5x、TypeScript で確認済み

実行とデバッグ

やりたいことコード
新規プロジェクト npm init playwright@latest
すべてのテストを実行 npx playwright test
1 ファイルの特定の行 npx playwright test tests/login.spec.ts:12
タイトルやタグで絞り込む npx playwright test --grep @smoke
1 つのブラウザプロジェクト npx playwright test --project=chromium
ブラウザを表示する npx playwright test --headed
Inspector でステップ実行 npx playwright test --debug
UI モード(ウォッチ、タイムトラベル) npx playwright test --ui
前回失敗したテストだけ npx playwright test --last-failed
フレーキーテストを探す npx playwright test my.spec.ts --repeat-each=20
CI マシン間でシャーディング npx playwright test --shard=1/4
HTML レポートを開く npx playwright show-report
トレースを開く npx playwright show-trace trace.zip
スクリプトを記録する npx playwright codegen https://example.com

ロケーター(推奨順)

やりたいことコード
ロールとアクセシブルネーム page.getByRole('button', { name: 'Sign in' })
ラベルでフォーム項目を指定 page.getByLabel('Email')
プレースホルダーで指定 page.getByPlaceholder('Search')
テキストで指定(完全一致) page.getByText('Welcome back', { exact: true })
テスト ID で指定(data-testid) page.getByTestId('checkout-submit')
CSS page.locator('#orders tbody tr')
XPath page.locator('xpath=//table[@id="orders"]//tr')
テキストで絞り込む page.getByRole('row').filter({ hasText: 'Mei Lin' })
子要素で絞り込む page.getByRole('listitem').filter({ has: page.getByRole('button', { name: 'Buy' }) })
一致した要素の中をさらに検索 row.getByRole('button', { name: 'Cancel' })
複数の中から 1 つを選ぶ .first() .last() .nth(2)
iframe の中 page.frameLocator('#payment').getByLabel('Card number')

ロケーターは遅延評価です。操作やアサーションを行うまで要素は検索されないので、一度定義して使い回せます。

操作

やりたいことコード
ページ遷移(baseURL からの相対パス) await page.goto('/login')
クリック await locator.click()
入力欄の値を置き換える await locator.fill('mei@example.com')
1 キーずつ入力する await locator.pressSequentially('abc', { delay: 50 })
キーを押す await locator.press('Enter')
チェックボックス・ラジオボタン await locator.check() / await locator.uncheck()
選択肢を選ぶ await page.getByLabel('Country').selectOption('UK')
ファイルをアップロード await locator.setInputFiles('fixtures/invoice.pdf')
ホバー await locator.hover()
ドラッグ&ドロップ await source.dragTo(target)
次のダイアログを承認する page.once('dialog', (d) => d.accept())

Web ファーストアサーション

やりたいことコード
表示 / 非表示 await expect(locator).toBeVisible() / .toBeHidden()
テキストの完全一致 await expect(locator).toHaveText('Order placed')
テキストを含む await expect(locator).toContainText('placed')
入力値 await expect(input).toHaveValue('42')
一致する要素の数 await expect(page.getByRole('row')).toHaveCount(5)
有効 / 無効 / チェック済み toBeEnabled() toBeDisabled() toBeChecked()
属性 await expect(menu).toHaveAttribute('aria-expanded', 'true')
URL とタイトル await expect(page).toHaveURL(/dashboard/) / .toHaveTitle('Orders')
否定 await expect(spinner).not.toBeVisible()
失敗しても続行する await expect.soft(total).toHaveText('£40.00')
任意の非同期チェックを再試行 await expect.poll(async () => (await api.get(url)).status()).toBe(200)
ビジュアル比較 await expect(page).toHaveScreenshot('home.png')

ネットワークと API

やりたいことコード
レスポンスをモックする await page.route('**/api/orders', (r) => r.fulfill({ json: [] }))
リクエストを失敗させる await page.route('**/api/orders', (r) => r.abort())
実際のレスポンスを書き換える await page.route('**/api/me', async (r) => { const res = await r.fetch(); const json = await res.json(); await r.fulfill({ response: res, json: { ...json, plan: 'pro' } }); })
レスポンスを待つ
const res = page.waitForResponse('**/api/orders');
await page.getByRole('button', { name: 'Save' }).click();
expect((await res).ok()).toBeTruthy();
API テスト
test('list users', async ({ request }) => {
  const res = await request.get('/api/users');
  await expect(res).toBeOK();
  expect(await res.json()).toHaveLength(3);
});

構造、フィクスチャ、フック

やりたいことコード
テストをグループ化 test.describe('checkout', () => { /* tests */ })
各テストの前に実行 test.beforeEach(async ({ page }) => { await page.goto('/'); })
テストにタグを付ける test('pays by card', { tag: '@smoke' }, async ({ page }) => { /* ... */ })
条件付きでスキップ test.skip(browserName === 'webkit', 'Not supported on WebKit')
ファイル内で並列実行 test.describe.configure({ mode: 'parallel' })
カスタムフィクスチャ
export const test = base.extend<{ loginPage: LoginPage }>({
  loginPage: async ({ page }, use) => { await use(new LoginPage(page)); },
});
ログイン済みの状態を再利用 test.use({ storageState: 'playwright/.auth/user.json' })
レポートにステップ名を付ける await test.step('add to cart', async () => { /* ... */ })

playwright.config.ts

設定例
page.goto のベース URL use: { baseURL: 'http://localhost:3000' }
失敗時の証跡 use: { trace: 'on-first-retry', screenshot: 'only-on-failure', video: 'retain-on-failure' }
CI でのみリトライ retries: process.env.CI ? 2 : 0
並列実行 fullyParallel: true, workers: process.env.CI ? 2 : undefined
test.only がコミットされたら失敗させる forbidOnly: !!process.env.CI
先にアプリを起動する webServer: { command: 'npm run start', url: 'http://localhost:3000', reuseExistingServer: !process.env.CI }
ブラウザ projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }]
デフォルトのタイムアウト timeout: 30_000, expect: { timeout: 5_000 }

練習してさらに学ぶ

その他のチートシート

キーワードを入力すると SDETRole 全体を検索できます。

Pagefind による全文検索 · ブラウザ内で動作します 検索ページを開く →