※ この記事の日本語には、少し不自然な部分があるかもしれません。AIの言語サポートを利用しながら作成しています。
目次
- はじめに
- 1. Playwrightとは
- 2. 実践的なユースケース
- 3. Playwright機能総合リファレンス
- 4. Library vs Test – どちらを選ぶか
- 5. ベストプラクティス
- 6. まとめ
- 最後に
はじめに
この記事は、Playwrightを「E2Eテストツール」としてしか知らないエンジニア、またはブラウザ自動化に興味があるが「どこから始めればいいかわからない」という方を対象としています。
筆者について:私は現在、日本市場向けのシステム開発を手がけるTOMOSIA VIETNAMでエンジニアとして働いています。実プロジェクトでPlaywrightをテストだけでなく、スクレイピングや運用自動化など多岐にわたって活用してきた経験をもとに、本記事を執筆しました。
この記事の目的:
- Playwrightが単なる「E2Eテストツール」ではなく、ブラウザ自動化エンジンとして幅広いユースケースを持つことを伝える
- クローリング、セッション管理、ネットワークモック、スクリーンショット、CIデバッグなど、実践的な使い方を具体的に紹介する
- 機能一覧を表形式のリファレンスとしてまとめ、必要な時にすぐ引けるようにする
想定読者:
- Playwrightを触ったことがあるが「テスト以外にどう使えるか」知りたい方
- SeleniumやPuppeteerから乗り換えを検討している方
- ブラウザ自動化スクリプトを書く機会があるエンジニア
Playwright for Dev — テストだけのためではない
概要: Playwrightはしばしば「E2Eテストツール」とレッテル貼られますが、実際にはブラウザ自動化エンジンです。クローリング、セッション保存、ネットワークモック、スクリーンショット、本番バグのデバッグ、CIでの自動化スクリプト実行など、幅広く活用できます。本記事ではPlaywrightを紹介し、実践的なユースケースを列挙し、機能を表形式でまとめました。
1. Playwrightとは
1.1 Playwrightの定義
Playwright はMicrosoftが開発したブラウザ自動化ライブラリで、オープンソースです。Node.js、Python、Java、.NETから実ブラウザ(Chromium、Firefox、WebKit)を制御できます。
fetch や curl のようなHTTPリクエスト送信とは異なり、Playwrightは完全なブラウザを実行します。JavaScriptのレンダリング、Cookie、iframe、ポップアップ、ファイルダウンロードなど、実際のユーザーがWeb上で経験するすべての動作を再現します。
Playwrightにはよく混同される2つの「顔」があります:
| Playwright Library |
Playwright Test (@playwright/test) |
|
|---|---|---|
| パッケージ | playwright |
@playwright/test |
| 目的 | 自由なスクリプト自動化 | E2Eテストフレームワーク |
| 構造 | async function main() |
test("...", async ({ page }) => {}) |
| アサーション | 自前で実装 |
expect() がビルトイン |
| レポート / トレース | 自前で設定 | HTMLレポート、リトライ時トレース |
両者は同じエンジンを使用します。「外側のラッパー」と「ワークフロー」が異なるだけです。
1.2 コアアーキテクチャ
スクリプトを書く前に理解すべき4つのレイヤー:
Browser → BrowserContext → Page → Locator
| レイヤー | 役割 | 例 |
|---|---|---|
| Browser | ブラウザエンジン |
chromium、firefox、webkit
|
| BrowserContext | 独立したセッション:Cookie、localStorage、権限 | ユーザーAとユーザーBの分離 |
| Page | コンテキスト内の1つのタブ | context.newPage() |
| Locator | 要素の検索と操作(自動待機付き) | page.getByRole("button") |
重要なルール: 1つの BrowserContext = 1つのセッション。異なるユーザーを並行テストしたい場合は、ブラウザを2つ起動する必要はなく、2つのコンテキストを作成します。
自動待機(Auto-wait): locator経由で click() や fill() を実行すると、Playwrightは自動的に要素が表示され、有効化され、安定するまで待機してから操作します。これは従来のSeleniumとの大きな違いであり、テストの「フレーク(不安定)」を大幅に削減します。
1.3 Selenium・Puppeteerとの比較
| 項目 | Playwright | Selenium | Puppeteer |
|---|---|---|---|
| 自動待機 | あり(デフォルト) | 制限あり、明示的待機が必要 | 一部あり |
| マルチブラウザ | Chromium、Firefox、WebKit | より広範囲(複数ドライバ) | 主にChromium |
| Cookie付きAPIリクエスト | context.request |
困難(Cookieを自前管理) |
page.setCookie あり |
| テストフレームワーク内蔵 | @playwright/test |
JUnit、pytestなどが必要 | なし |
| トレース / デバッグツール | 強力(タイムライン、ネットワーク、DOM) | 弱い | 基本機能 |
| コミュニティとドキュメント | 急成長中 | 大規模、長い歴史 | Google、Chromium中心 |
1.4 導入すべきケース
- JavaScriptでレンダリングされるサイト(SPA、React、Vue…)—
fetchだけでは不十分 - OAuth / Google / SSO経由のログインが必要で、セッションを再利用したい
- ネットワークリクエストのインターセプトやモックが必要
- CI(GitHub Actions、GitLab CI)でヘッドレス実行したい
- トレース、スクリーンショット、動画でバグをデバッグしたい
- 複数ブラウザ(Chromium + Firefox + WebKit)でテストまたは自動化したい
1.5 クイックインストール
# Library(スクリプト自動化)
npm install playwright
npx playwright install chromium
# または Testフレームワーク
npm install -D @playwright/test
npx playwright install
Libraryを使った最小スクリプト:
import { chromium } from "playwright"
async function main() {
const browser = await chromium.launch({ headless: true })
const page = await browser.newPage()
await page.goto("https://example.com")
console.log(await page.title())
await browser.close()
}
main()
2. 実践的なユースケース
各ユースケースは 問題 → Playwrightでの解決策 → 主要API → 注意点 の形式で記載します。
2.1 E2Eテスト
問題: ユーザーの実際のフロー(ログイン→商品追加→チェックアウト)を単体テストだけでなく検証する必要がある。
解決策: @playwright/test とロケーター、アサーションを使用。
import { test, expect } from "@playwright/test"
test("ユーザーがログインできる", async ({ page }) => {
await page.goto("/login")
await page.getByLabel("メールアドレス").fill("user@example.com")
await page.getByLabel("パスワード").fill("secret")
await page.getByRole("button", { name: "ログイン" }).click()
await expect(page.getByText("ようこそ")).toBeVisible()
})
主要API: test()、expect()、getByRole、getByLabel
注意点: これが最も一般的なユースケースですが、Playwrightの機能はこれだけではありません。
2.2 Webスクレイピング / 動的コンテンツのクローリング
問題: fetch や curl は静的なHTMLしか取得できない。SPAはJavaScriptでデータを読み込むため、ブラウザなしではコンテンツが取得できない。
解決策: ページを開き、要素の出現を待ち、HTMLを取得するか、ページ内でJSを実行する。
const browser = await chromium.launch({ headless: true })
const page = await browser.newPage()
await page.goto("https://example.com/courses", { waitUntil: "domcontentloaded" })
await page.waitForSelector(".course-list")
const html = await page.content()
// Cheerioや正規表現でHTMLをパース
await browser.close()
主要API: page.goto、waitForSelector、page.content()、page.evaluate()
注意点: robots.txtと利用規約を遵守すること。レート制限とリトライを追加してIPブロックを回避すること。
2.3 セッションの保存と再利用(OAuth・2FA)
問題: Google OAuthや2FAを使用するサイトでは、スクリプト内で完全に自動ログインすることができない。
解決策: 一度だけ手動でログインし(ブラウザ表示)、storageState を保存する。以降の実行ではそのセッションを読み込む。
// ステップ1: save-session.ts — 1回だけ実行、headless: false
const context = await browser.newContext()
const page = await context.newPage()
await page.goto("https://app.example.com/login")
// ユーザーが手動でログインし、ターミナルでEnterを押す
await context.storageState({ path: "auth.json" })
// ステップ2: crawl.ts — headlessで実行、保存したセッションを使用
const context = await browser.newContext({ storageState: "auth.json" })
主要API: context.storageState()、newContext({ storageState })
注意点: auth.json ファイルにはCookieが含まれるため、Gitにコミットしてはいけません。セッションは期限切れになる可能性があるため、リフレッシュフローが必要です。
2.4 ブラウザコンテキストでのAPIテスト
問題: バックエンドAPIはブラウザからのCookie/セッションを要求する。Nodeから fetch を呼び出してもそのCookieがない。
解決策: context.request を使用すると、コンテキストのCookieが自動的に送信される。
const context = await browser.newContext({ storageState: "auth.json" })
const response = await context.request.get("https://api.example.com/me", {
headers: { Accept: "application/json" },
})
const data = await response.json()
console.log(data)
主要API: context.request.get()、.post()、.put()、.delete()
注意点: JSONデータだけが必要な場合、UIページを開くより高速です。ログイン後のAPIクローリングに最適です。
2.5 ネットワークのモックとブロック
問題: バックエンドが未完成の状態でフロントエンドをテストしたい。または、広告/アナリティクスをブロックして高速化したい。
解決策: page.route() でパターンに一致するリクエストをインターセプトする。
// APIのモック
await page.route("**/api/users", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify([{ id: 1, name: "モックユーザー" }]),
})
})
// 画像とフォントをブロックして高速化
await page.route("**/*.{png,jpg,woff2}", (route) => route.abort())
主要API: page.route()、route.fulfill()、route.abort()、route.continue()
注意点: モックはそのコンテキスト/ページ内でのみ有効です。テストや開発環境で使用し、本番クローリングには使用しないでください。
2.6 スクリーンショット・PDF・ビジュアルリグレッション
問題: Webページのスクリーンショットを撮ったり、PDFを出力したり、変更前後のUIを比較したい。
解決策:
// 全ページのスクリーンショット
await page.screenshot({ path: "page.png", fullPage: true })
// 特定要素のスクリーンショット
await page.locator(".hero-banner").screenshot({ path: "hero.png" })
// PDF出力(Chromiumのみ)
await page.pdf({ path: "report.pdf", format: "A4" })
主要API: page.screenshot()、page.pdf()、locator.screenshot()
注意点: ビジュアルリグレッションテストは @playwright/test + expect(page).toHaveScreenshot() またはサードパーティツールと組み合わせて行います。
2.7 デバッグとバグ再現
問題: CIでテストが失敗するがローカルでは成功する — 再現が難しい。
解決策: トレース、失敗時スクリーンショット、動画を有効にする。
// playwright.config.ts 内
export default defineConfig({
use: {
trace: "on-first-retry",
screenshot: "only-on-failure",
video: "retain-on-failure",
},
})
失敗後:npx playwright show-trace trace.zip — 各アクションのタイムライン、ネットワーク、DOMスナップショットを表示。
ツール: playwright codegen はマウス/キーボード操作を記録 → コードを自動生成します。
npx playwright codegen https://example.com
2.8 自動化ワークフロー(テスト以外)
問題: 繰り返しタスク(フォーム一括入力、ポータルからのデータエクスポート、2システム間の同期)を自動化したい。
解決策: Libraryスクリプトを書き、@playwright/test は使用しない。
import { chromium } from "playwright"
async function exportReport() {
const browser = await chromium.launch({ headless: false })
const page = await browser.newPage()
await page.goto("https://portal.example.com/reports")
await page.getByRole("button", { name: "CSVをエクスポート" }).click()
const download = await page.waitForEvent("download")
await download.saveAs("./report.csv")
await browser.close()
}
exportReport()
主要API: waitForEvent("download")、ロケーター、fill、click
注意点: headless: false はCAPTCHAを手動処理する必要がある場合に便利です。
2.9 モバイル・レスポンシブチェック
問題: 実機がなくてもモバイルサイズでのUIを簡易チェックしたい。
解決策: デバイスプリセットまたはカスタムビューポートを使用。
import { chromium, devices } from "playwright"
const browser = await chromium.launch()
const context = await browser.newContext({
...devices["iPhone 13"],
locale: "ja-JP",
})
const page = await context.newPage()
await page.goto("https://example.com")
主要API: devices、viewport、userAgent、hasTouch、isMobile
注意点: エミュレーションは実機テストの代替にはなりません — スモークテストとレイアウトチェックに適しています。
2.10 CI/CDパイプライン
問題: コードプッシュごとに自動的にテスト/自動化を実行したい。
解決策: 公式Dockerイメージ + GitHub Actions。
# .github/workflows/e2e.yml
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci
- run: npx playwright install --with-deps chromium
- run: npx playwright test
- uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-report
path: playwright-report/
CI機能: 並列ワーカー、リトライ、HTMLレポートのアーティファクト、失敗時トレース。
3. Playwright機能総合リファレンス
グループ別のクイックリファレンスです。API / コマンド はTypeScript/Node.jsで記述しています。
3.1 ブラウザとコンテキスト
| 機能 | API / コマンド | 説明 | ユースケース |
|---|---|---|---|
| ブラウザ起動 |
chromium.launch()、firefox.launch()、webkit.launch()
|
ブラウザエンジンを起動 | すべての自動化 |
| Headless / Headed | { headless: true | false } |
非表示または表示で実行 | CI vs デバッグ |
| スローモーション | { slowMo: 100 } |
各操作を遅延(ms) | フローの観察 |
| DevTools | { devtools: true } |
起動時にDevToolsを開く | デバッグ |
| プロキシ | { proxy: { server: "..." } } |
プロキシ経由でルーティング | Geo制限、企業ネットワーク |
| 新コンテキスト | browser.newContext(options) |
新しいセッション作成(Cookie個別) | マルチユーザー |
| 永続コンテキスト | chromium.launchPersistentContext(userDataDir) |
実ブラウザプロファイルを使用 | 長期ログイン維持 |
| ブラウザ終了 | browser.close() |
ブラウザを閉じてリソース解放 | クリーンアップ |
| コンテキスト終了 | context.close() |
コンテキストを閉じる | クリーンアップ |
3.2 ナビゲーション
| 機能 | API / コマンド | 説明 | ユースケース |
|---|---|---|---|
| URLを開く | page.goto(url, options) |
URLに遷移 | すべてのフロー |
| Wait until | waitUntil: "load" | "domcontentloaded" | "networkidle" | "commit" |
ロード完了条件 | SPA vs 静的なサイト |
| タイムアウト | { timeout: 30_000 } |
待機時間の制限 | 無限待機の防止 |
| 戻る | page.goBack() |
ブラウザの戻る | 複数ステップフロー |
| 進む | page.goForward() |
ブラウザの進む | — |
| リロード | page.reload() |
ページを再読み込み | 状態のリセット |
| 現在のURL | page.url() |
URLを読み取り | リダイレクトのアサート |
| タイトル | page.title() |
タブのタイトルを読み取り | スモークチェック |
3.3 ロケーターとUI操作
| 機能 | API / コマンド | 説明 | ユースケース |
|---|---|---|---|
| Role別 | page.getByRole("button", { name: "..." }) |
アクセシビリティroleで検索 | ボタン、リンク、見出し |
| Text別 | page.getByText("ログイン") |
表示テキストで検索 | testidがないUI |
| Label別 | page.getByLabel("メール") |
<label>付きinput |
フォーム |
| Placeholder別 | page.getByPlaceholder("メールを入力") |
placeholder付きinput | フォーム |
| Alt text別 | page.getByAltText("ロゴ") |
alt属性付き画像 | アクセシビリティ |
| Title別 | page.getByTitle("ツールチップ") |
title属性付き要素 | アイコンボタン |
| Test ID別 | page.getByTestId("submit-btn") |
data-testid 属性 |
安定したテスト |
| CSS / XPath |
page.locator(".class")、page.locator("xpath=...")
|
任意のセレクタ | レガシーDOM |
| フィルタ | locator.filter({ hasText: "..." }) |
ロケーターセット内でフィルタ | リスト項目 |
| Nth / first / last |
locator.nth(0)、.first()、.last()
|
リストから要素を選択 | テーブル行 |
| クリック | locator.click() |
要素をクリック | ボタン、リンク |
| ダブルクリック | locator.dblclick() |
ダブルクリック | デスクトップUI |
| 右クリック | locator.click({ button: "right" }) |
コンテキストメニュー | — |
| 入力 | locator.fill("text") |
入力欄に入力(事前クリア) | 高速フォーム入力 |
| タイプ | locator.pressSequentially("text") |
一文字ずつ入力 | タイピングのシミュレート |
| キー押下 | locator.press("Enter") |
キーを押す | フォーム送信 |
| チェック / アンチェック |
locator.check()、.uncheck()
|
チェックボックス操作 | フォーム |
| オプション選択 | locator.selectOption("value") |
ドロップダウン <select>
|
フォーム |
| ホバー | locator.hover() |
要素にマウスオーバー | ツールチップ、メニュー |
| ドラッグ&ドロップ | locator.dragTo(target) |
ドラッグ&ドロップ | カンバン、アップロード |
| ファイルアップロード | locator.setInputFiles("path/to/file") |
input file経由でアップロード | インポート |
| フォーカス / ブラー |
locator.focus()、.blur()
|
フォーカス操作 | キーボードナビ |
| スクロール | locator.scrollIntoViewIfNeeded() |
要素までスクロール | 要素がビューポート外 |
| フレーム | page.frameLocator("iframe").getByRole(...) |
iframe内で操作 | 埋め込み、ウィジェット |
| カウント | await locator.count() |
一致する要素数をカウント | リスト長のアサート |
| 内部テキスト / HTML |
locator.innerText()、.innerHTML()
|
要素の内容を読み取り | スクレイピング |
3.4 待機と同期
| 機能 | API / コマンド | 説明 | ユースケース |
|---|---|---|---|
| セレクタ待機 | page.waitForSelector(".class") |
要素がDOMに現れるまで待機 | SPAの遅延ロード |
| URL待機 | page.waitForURL("**/dashboard") |
URLがパターンに一致するまで待機 | ログイン後のリダイレクト |
| ロード状態待機 | page.waitForLoadState("networkidle") |
ネットワークがアイドルになるまで待機 | 遷移後 |
| レスポンス待機 | page.waitForResponse("**/api/data") |
APIレスポンスが返るまで待機 | AJAXヘビーなアプリ |
| リクエスト待機 | page.waitForRequest("**/api/save") |
リクエストが送信されるまで待機 | API呼び出しの検証 |
| 関数待機 | page.waitForFunction(() => window.dataReady) |
ページ内JS条件が成立するまで待機 | カスタムロジック |
| タイムアウト待機 | page.waitForTimeout(1000) |
固定時間待機(ms) | 避けるべき — auto-waitを使用 |
| イベント待機 | page.waitForEvent("popup") |
ブラウザイベントを待機 | ポップアップ、ダウンロード |
| Auto-wait(ビルトイン) | すべてのlocatorアクション | 表示・有効・安定を自動待機 | フレークの軽減 |
3.5 ネットワーク
| 機能 | API / コマンド | 説明 | ユースケース |
|---|---|---|---|
| リクエストインターセプト | page.route("**/api/**", handler) |
送信前にリクエストをインターセプト | モック、ブロック |
| モック応答 | route.fulfill({ status, body }) |
偽のレスポンスを返す | バックエンド不要のテスト |
| リクエスト中止 | route.abort() |
リクエストをキャンセル | 広告、画像のブロック |
| リクエスト継続 | route.continue() |
リクエストをそのまま通す(ヘッダー変更可) | ヘッダー修正 |
| リクエスト監視 | page.on("request", cb) |
すべてのリクエストを監視 | トラフィックデバッグ |
| レスポンス監視 | page.on("response", cb) |
すべてのレスポンスを監視 | APIデバッグ |
| リクエスト失敗監視 | page.on("requestfailed", cb) |
失敗したリクエストをキャッチ | ネットワークデバッグ |
| APIクライアント(GET) | context.request.get(url) |
コンテキストのCookie付きHTTP GET | APIクローリング |
| APIクライアント(POST) | context.request.post(url, { data }) |
HTTP POST | フォームAPI、JSON API |
| APIクライアント(form) | context.request.post(url, { form }) |
POST form-urlencoded | WordPress ajax |
| HAR記録 |
recordHar: { path: "out.har" } in context options |
HTTPトラフィック全体を記録 | 監査、リプレイ |
| HARリプレイ | routeFromHAR("file.har") |
HARからリクエストをリプレイ | 安定したテスト |
3.6 認証・Cookie・ストレージ
| 機能 | API / コマンド | 説明 | ユースケース |
|---|---|---|---|
| セッション保存 | context.storageState({ path: "auth.json" }) |
Cookie + localStorageを保存 | 1回だけログイン |
| セッション読み込み | browser.newContext({ storageState: "auth.json" }) |
セッションを復元 | クローリング、テスト |
| Cookie読み取り | context.cookies() |
Cookie一覧を取得 | 認証デバッグ |
| Cookie追加 | context.addCookies([...]) |
手動でCookieを追加 | セッション注入 |
| Cookieクリア | context.clearCookies() |
Cookieを削除 | 状態リセット |
| HTTP Basic認証 | { httpCredentials: { username, password } } |
Basic認証 | 認証保護サイト |
| 権限付与 | context.grantPermissions(["geolocation"]) |
ブラウザ権限を付与 | 権限UIのテスト |
| 位置情報 | { geolocation: { latitude, longitude } } |
位置情報をエミュレート | 地図、デリバリーアプリ |
| ロケール | { locale: "ja-JP" } |
ブラウザの言語 | i18nテスト |
| タイムゾーン | { timezoneId: "Asia/Tokyo" } |
タイムゾーン | 日付/時刻UI |
| カラースキーム | { colorScheme: "dark" } |
ダーク / ライトモード | テーマテスト |
| HTTPヘッダー | { extraHTTPHeaders: { ... } } |
全リクエストのデフォルトヘッダー | APIキー、カスタムUA |
| User-Agent | { userAgent: "..." } |
ブラウザ/OSをエミュレート | アンチボット、モバイル |
3.7 ブラウザ内JavaScript
| 機能 | API / コマンド | 説明 | ユースケース |
|---|---|---|---|
| JS実行 | page.evaluate(fn, arg) |
ページ内で関数を実行、Nodeを返す |
window.* の読み取り |
| Evaluate handle | page.evaluateHandle(fn) |
JSHandleオブジェクトを返す | 複雑なオブジェクト操作 |
| Initスクリプト | context.addInitScript(fn) |
各ナビゲーション前にスクリプトを注入 | 検出回避、モック |
| 関数公開 | page.exposeFunction("myFn", nodeFn) |
ブラウザからNode関数を呼び出し | ロジックブリッジ |
| ページコンテンツ | page.content() |
レンダリング後の完全なHTML | スクレイピング |
| コンテンツ設定 | page.setContent(html) |
HTMLを直接設定 | コンポーネント単体テスト |
3.8 ポップアップ・ダイアログ・ダウンロード
| 機能 | API / コマンド | 説明 | ユースケース |
|---|---|---|---|
| 新タブ / ウィンドウ | page.waitForEvent("popup") |
target=_blank のポップアップをキャッチ |
OAuth、新タブ |
| 全ページ | context.pages() |
開いているすべてのタブを一覧表示 | マルチタブフロー |
| Alert / Confirm / Prompt | page.on("dialog", async d => d.accept()) |
ネイティブダイアログを処理 | 削除確認 |
| ファイルダウンロード | page.waitForEvent("download") |
ダウンロードイベントをキャッチ | CSV、PDFエクスポート |
| ダウンロード保存 | download.saveAs("path") |
ダウンロードファイルを保存 | 自動化エクスポート |
3.9 キャプチャとエクスポート
| 機能 | API / コマンド | 説明 | ユースケース |
|---|---|---|---|
| ページスクリーンショット | page.screenshot({ path }) |
現在のビューポートを撮影 | デバッグ |
| 全ページスクリーンショット | page.screenshot({ fullPage: true }) |
ページ全体を撮影(スクロール) | ランディングページ監査 |
| 要素スクリーンショット | locator.screenshot({ path }) |
特定要素を撮影 | コンポーネントビジュアル |
| PDFエクスポート | page.pdf({ path, format: "A4" }) |
ページをPDF出力 | レポート(Chromiumのみ) |
| 動画録画 |
{ recordVideo: { dir: "videos/" } } in context |
セッションを動画録画 | バグ再現 |
| トレース |
context.tracing.start()、.stop({ path })
|
タイムライントレースを記録 | CI障害デバッグ |
| メディアエミュレート | page.emulateMedia({ media: "print" }) |
print/screenメディアをエミュレート | 印刷スタイルシート |
3.10 デバイスとエミュレーション
| 機能 | API / コマンド | 説明 | ユースケース |
|---|---|---|---|
| ビューポートサイズ | { viewport: { width, height } } |
ウィンドウサイズ | レスポンシブテスト |
| デバイスプリセット |
devices["iPhone 13"] spread into context |
完全なモバイルエミュレーション | モバイルスモークテスト |
| モバイルフラグ | { isMobile: true } |
ページにモバイルを示す | タッチ動作 |
| タッチサポート | { hasTouch: true } |
タッチイベントをサポート | モバイルフロー |
| デバイススケール | { deviceScaleFactor: 2 } |
Retina / DPI | 正しい解像度のスクリーンショット |
| オフラインモード | context.setOffline(true) |
ネットワーク切断をエミュレート | オフラインUIテスト |
| CPUスロットル |
context.route + slow 3G emulation |
低速ネットワークをエミュレート | パフォーマンスUX |
3.11 Playwright Test(テストフレームワーク)
| 機能 | API / コマンド | 説明 | ユースケース |
|---|---|---|---|
| テストケース | test("name", async ({ page }) => {}) |
テストを定義 | E2Eスイート |
| テストグループ | test.describe("group", () => {}) |
テストをグループ化 | テスト整理 |
| Skip / only |
test.skip()、test.only()
|
スキップ / 特定テストのみ実行 | デバッグ |
| Before each | test.beforeEach(async ({ page }) => {}) |
各テスト前のセットアップ | ログイン、ナビゲート |
| After each | test.afterEach(async () => {}) |
各テスト後のクリーンアップ | データリセット |
| アサーション | expect(locator).toBeVisible() |
UI状態をアサート | 動作検証 |
| テキストアサート | expect(locator).toHaveText("...") |
テキスト内容をアサート | コンテンツチェック |
| URLアサート | expect(page).toHaveURL("...") |
URLをアサート | リダイレクトチェック |
| スクリーンショットアサート | expect(page).toHaveScreenshot() |
画像を比較 | ビジュアルリグレッション |
| Soft assert | expect.soft(locator).toBeVisible() |
テストを停止せずにアサート | 複数エラー収集 |
| Fixtures | test.extend({ myFixture }) |
カスタムセットアップ/ティアダウン | ロジック再利用 |
| ビルトインFixtures |
page、context、browser、request
|
自動インジェクション | 高速テスト |
| 並列実行 |
{ workers: 4 } in config |
テストを並列実行 | CIスループット |
| リトライ | { retries: 2 } |
失敗時に自動リトライ | フレーク軽減 |
| タイムアウト | { timeout: 30_000 } |
各テストのタイムアウト | 無限待機防止 |
| Projects | projects: [{ name, use }] |
ブラウザ/デバイスのマトリックス | クロスブラウザ |
| Reporter HTML | reporter: "html" |
HTMLレポート | 結果レビュー |
| Reporter JUnit | reporter: "junit" |
CI用XML | Jenkins、GitLab |
| Global setup | globalSetup: "./setup.ts" |
スイート前に1回実行 | 共有認証 |
| Global teardown | globalTeardown: "./teardown.ts" |
スイート後に1回実行 | クリーンアップ |
| Test step | await test.step("login", async () => {}) |
レポート内でアクションをグループ化 | 可読性向上 |
| Tag | test("name", { tag: "@smoke" }) |
タグを付けてフィルタ | npx playwright test --grep @smoke |
3.12 CLIとツーリング
| コマンド | 説明 | ユースケース |
|---|---|---|
npx playwright install |
ブラウザバイナリをダウンロード | 初回セットアップ |
npx playwright install chromium |
Chromiumのみダウンロード | ディスク容量節約 |
npx playwright codegen [url] |
操作を記録 → コード生成 | API学習、プロトタイプ |
npx playwright test |
全テストスイートを実行 | ローカル / CI |
npx playwright test --ui |
UIモードで実行 | インタラクティブデバッグ |
npx playwright test --debug |
Inspectorでステップ実行 | テスト障害デバッグ |
npx playwright show-report |
HTMLレポートを表示 | CI後レビュー |
npx playwright show-trace trace.zip |
トレースファイルを表示 | タイムラインデバッグ |
npx playwright open [url] |
Playwrightでブラウザを開く | クイックテスト |
npx playwright --version |
バージョン確認 | 互換性チェック |
4. Library vs Test – どちらを選ぶか
| 項目 | Playwright Library | @playwright/test |
|---|---|---|
| 使用するケース | クローリング、ボット、単発自動化スクリプト | アサーション付きE2Eテスト、CIテストスイート |
| コード構造 |
async function main() 自由形式 |
test() + expect()
|
| 並列実行 | 自前で実装 | Configの workers
|
| レポート |
console.log または自前ビルド |
HTML、JUnitがビルトイン |
| トレース / 動画 |
tracing.start() を自前で有効化 |
playwright.config.ts で設定 |
| リトライ | 自前でループ実装 | Configの retries
|
| Fixtures | なし |
test.extend、page ビルトイン |
実践的なアドバイス:
- Library から始めるのがおすすめ(クローリング、エクスポート、データ同期が目的の場合)
- Test に移行するタイミング:アサーション、レポート、CIマトリックス、チームでのテスト維持が必要になった時
- 混在も可能:
globalSetupでLibraryを使ってログインしstorageStateを保存、テストではそのファイルを使用する
5. ベストプラクティス
ロケーター
- 優先順位:
getByRole→getByLabel→getByText→getByTestId→locator(css) - 不安定なセレクタを避ける:
div > div > span:nth-child(3) - 重要な要素には
data-testidを使用する
待機
- locatorのauto-waitを信頼する — クリック後に
sleep(3000)は不要 -
waitForTimeoutの代わりにwaitForResponseまたはwaitForURLを使用する -
networkidleはWebSocketがあるSPAでタイムアウトしやすい —domcontentloaded+waitForSelectorを優先
認証
- ログインは
globalSetupまたは別のsave-sessionスクリプトに切り出す -
storageStateファイルはコミットしない —.gitignoreに追加する - セッション期限切れをチェック:401/403をキャッチして再ログインをトリガーする
CI
- Linux CIでは
npx playwright install --with-depsを使用する -
trace: "on-first-retry"を有効にし、失敗時にアーティファクトをアップロードする - 並列実行するが、各テストでコンテキストを分離する
クローリング / 本番スクリプト
- リクエスト間にレート制限を設ける(
delay500ms–2s) - 429/503が発生したら指数バックオフでリトライする
- 進捗をファイルにログ出力し、中断時に再開できるようにする
- robots.txtと利用規約を尊重する
6. まとめ
Playwrightは単なる「テストを書くツール」ではありません。ブラウザ自動化の基盤です。同じエンジンで以下のことができます:
- E2Eテスト
- 動的コンテンツのクローリング
- OAuthセッションの保存
- APIモック
- スクリーンショット撮影
- CI上でのバグデバッグ
- ワークフロー自動化
コアな強み:
- Auto-wait で従来の自動化よりフレークが少ない
- マルチブラウザ(Chromium、Firefox、WebKit)を単一APIで制御
-
context.requestでセッションCookie付きAPI呼び出し -
storageStateで複雑なログインを再利用 - トレース & codegen でデバッグと学習が高速
次のステップ:
- 公式ドキュメントを読む:playwright.dev/docs
- 使い慣れたサイトで
npx playwright codegenを試す - 小さなLibraryスクリプト(goto → scrape → close)を書く
- CIが必要になったら
@playwright/test+ GitHub Actions を追加する
参考資料: Playwright Documentation · API Reference
最後に
ここまでお読みいただき、誠にありがとうございます。
もし**「システム開発を依頼したい」「技術的な相談をしたい」「AIを活用した課題解決のアイデアがある」** といったお悩みがございましたら、ぜひ私たちTOMOSIA VIETNAMにご相談ください。
私たちの主なサービス
- 💻 ソフトウェア受託開発(Web・アプリ・システム)
- 🤖 AIソリューション(チャットボット、画像処理、LLM応用)
- 📱 モバイルアプリ開発(iOS / Android)
- 🔌 Fintech / IoT開発
- 🔧 ブリッジSE(BrSE)支援(日本語でのコミュニケーションをスムーズに)
私たちの強み
- ISO/IEC 27001(情報セキュリティ)認証取得済み – 安心して任せていただけます
- 日本語対応チーム – 日本の文化・ビジネス習慣を理解したメンバーが直接対応
- 「Win-Win, Happy Together」の文化 – 長期的なパートナーシップを大切にします
🔗 公式サイト: tomosia.com
まずはお気軽に、一言ご連絡ください。私たちと一緒に、「ベトナムの知恵」で世界に挑戦しませんか?
---