Playwrightの使い方は、npm init playwright@latest で雛形を作り、test と expect でテストを書き、npx playwright test で流してHTMLレポートを読む、という4つの作業に集約されます。この記事では、ログイン画面を題材に最初のE2Eテストを1本書き、ログイン状態の使い回しとGitHub Actionsでの自動実行まで、そのまま動かせるコードで順に進めます。手順と既定値は公式ドキュメントの1.65系(2026年11月時点)の記述に合わせました。
まとめ:Playwrightの使い方は初期化・記述・実行・CI化の4工程
- 初期化:
npm init playwright@latestで設定ファイル・サンプルテスト・ブラウザがそろう。最初に playwright.config.ts の baseURL と webServer を決める。 - 記述:要素は
getByRoleとgetByLabelで指定し、検証は自動で待つawait expect(...)で書く。固定秒数の待機は入れない。 - 実行:普段は
npx playwright test、原因を追うときはUIモードかトレースで失敗したステップの画面を見る。 - 認証:ログインはsetupプロジェクトで1回だけ行い、保存した状態ファイルを全テストで読み込む。状態ファイルはGitに入れない。
- CI化:初期化時に生成できるGitHub Actionsのワークフローで、失敗時もレポートを成果物として30日残す。
- 自動化は売上と認証に直結する主要導線5本前後から始め、画面仕様が毎週変わる段階では後回しにする。
npm init playwrightでテスト環境を初期化して生成ファイルを確かめる
Playwright Test はテストランナー・アサーション・ブラウザ制御が1パッケージにまとまっているので、JestやMochaを別に入れる必要はありません。最初の作業は雛形の生成で、ここで決めた設定がその後のテストすべての前提になります。Playwright自体の仕組みやSeleniumとの違いから押さえたい場合は、先にPlaywright(プレイライト)とは?仕組み・できること・Seleniumとの違いを読んでおくと流れが掴みやすくなります。
Node.jsとOSの対応範囲を確かめてから初期化コマンドを実行する
公式のInstallationページでは、対応環境がNode.js 22.x・24.x・26.xの最新版、Windows 11以降またはWSL、macOS 14以降、Debian 12/13とUbuntu 22.04/24.04/26.04と示されています。古いNode.jsのまま始めると、ここで止まります。
初期化コマンドは対話形式で、言語(既定はTypeScript)、テストフォルダ名(既定は tests)、GitHub Actionsのワークフローを足すか、ブラウザを入れるか(既定は入れる)の4点を聞かれます。既存プロジェクトで再実行してもテストは上書きされません。
# 空のディレクトリで雛形を生成する
mkdir e2e-sample && cd e2e-sample
npm init playwright@latest
# 生成物:playwright.config.ts / package.json / package-lock.json / tests/example.spec.ts
# 入った版を確認する
npx playwright --version
社内プロキシ配下でブラウザのダウンロードが止まる、Windowsで実行できないといった導入時のつまずきはPlaywrightのインストール方法とできない時の対処で切り分けています。
playwright.config.tsのbaseURLとwebServerの事前設定
テストにURLを直書きすると、ステージングと本番で書き換えが必要になります。公式のConfigurationページにあるとおり、use.baseURL を決めておけば page.goto('/login') のような相対パスで書けます。webServer はテストの前に開発サーバーを起動する設定です。手元でサーバーを立ち上げ忘れて全件失敗する、という初歩の事故がなくなります。
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
],
webServer: {
command: 'npm run start',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
},
});
最初はプロジェクトをChromium1つに絞ると、実行時間が短く失敗の原因も追いやすくなります。FirefoxとWebKitは、主要導線のテストが安定してから projects に足せば十分です。
最初のテストをtest関数とexpectで書きログイン画面の動きを検証する
テストファイルは tests 配下に *.spec.ts の名前で置きます。公式のWriting testsページによると、各テストは独立したブラウザコンテキストで動くため、Cookieやストレージが前のテストから持ち越されることはありません。テスト同士の実行順に依存した書き方は不要です。
getByRoleとgetByLabelで画面の要素を指定する書き方と厳密モード
公式のLocatorsページは、CSSやXPathより、ボタンの役割と名前やラベル文字列のような利用者から見える属性で要素を指定する方法を推奨しています。DOMの階層を変えても壊れにくいからです。
// tests/login.spec.ts
import { test, expect } from '@playwright/test';
test('正しい認証情報でログインするとダッシュボードが表示される', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('メールアドレス').fill(process.env.E2E_USER ?? '');
await page.getByLabel('パスワード').fill(process.env.E2E_PASSWORD ?? '');
await page.getByRole('button', { name: 'ログイン' }).click();
await expect(page).toHaveURL(/\/dashboard/);
await expect(page.getByRole('heading', { name: 'ダッシュボード' })).toBeVisible();
});
ロケーターは厳密に動き、操作の対象が2つ以上見つかると「more than one element matches」で失敗します。first() や nth() で逃げる方法もありますが、画面が変わると別の要素を押すおそれがあるので、名前を足して1つに絞るほうが安全です。認証情報は環境変数から渡し、コードに書き込まないでください。
filterやandでの絞り込み、strict mode違反を直す順番はPlaywrightのlocator入門:getByRoleの書き方とstrict mode違反の直し方【1.65対応】で詳しく解説しています。
自動で待つWebファーストアサーションで固定秒数の待機をなくす
Playwrightはクリックや入力の前に、要素が表示され有効になるまで自動で待ちます。検証側も同じで、await expect(locator).toBeVisible() のような非同期マッチャーも、条件を満たすまで再試行する仕組みです。待つ上限は公式のTimeoutsページで、expectが5,000ms、テスト1本が30,000msと定められています。
| 書き方 | 待つか | 使う場面 |
|---|---|---|
| toBeVisible/toHaveText | 待つ | 画面の表示や文言の検証 |
| toHaveURL/toHaveTitle | 待つ | 画面遷移の検証 |
| toHaveCount/toHaveValue | 待つ | 一覧の件数や入力値の検証 |
| toEqual/toBeTruthy | 待たない | 取得済みの値の比較 |
失敗しやすいのは、textContent() で文字列を取り出してから toEqual で比べる書き方です。取り出した瞬間の値で判定するため、描画が遅れた回だけ落ちます。画面の状態は必ず locator を渡す形で検証し、waitForTimeout による固定秒数の待機は入れないでください。
test.describeとbeforeEachで共通の前処理をまとめるテストの構成
同じ画面のテストが3本を超えたら、test.describe でまとめて beforeEach に共通の遷移を移します。beforeAll と afterAll はワーカーごとに1回しか動かないため、テストごとに初期化したい処理は beforeEach 側に置きます。
import { test, expect } from '@playwright/test';
test.describe('問い合わせフォーム', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/contact');
});
test('必須項目が空なら送信できない', async ({ page }) => {
await page.getByRole('button', { name: '送信' }).click();
await expect(page.getByText('お名前を入力してください')).toBeVisible();
});
test('入力して送信すると完了画面に進む', async ({ page }) => {
await page.getByLabel('お名前').fill('テスト 太郎');
await page.getByLabel('お問い合わせ内容').fill('E2Eテストからの送信');
await page.getByRole('button', { name: '送信' }).click();
await expect(page).toHaveURL(/\/contact\/thanks/);
});
});
テストが十数本を超え、同じ画面の操作が複数ファイルに散らばってきたら、画面単位で操作をまとめる設計に移る時期です。判断材料はPage Object Model(POM)とは?Playwright・Seleniumの実装例と保守コストの実測で整理しました。テスト計画の作成から初版の生成までをAIエージェントに任せる方法はPlaywright Agentsの使い方:init-agentsの導入とplanner・generator・healerの実行手順【1.65対応】で手順を追っています。
npx playwright testで実行しUIモードとトレースで失敗の原因を追う
書いたテストは npx playwright test で流します。既定ではヘッドレスで並列に走り、失敗が1件でもあるとHTMLレポートが自動で開く仕組みです。ここでは日常の実行と、落ちたときの調べ方だけを扱います。ファイルやテスト名での絞り込み、失敗分だけの再実行といったオプションの全体像はPlaywright CLIコマンド一覧にまとめています。
ブラウザを表示して実行し動きを目で確かめるための3つのコマンド
# すべてのテストを実行する
npx playwright test
# 1ファイルだけ、ブラウザを表示して実行する
npx playwright test tests/login.spec.ts --headed --project=chromium
# 直前の実行結果をHTMLレポートで開く
npx playwright show-report
書き始めの数本は --headed で画面を出し、想定どおりの順で入力と遷移が進むかを目で見ておくと、ロケーターの指定ミスに早く気づけます。
UIモードとトレースビューアで失敗したステップの画面とログを追う
公式のUI Modeページが説明するUIモードは、テストの一覧から1本ずつ実行し、ステップごとのDOMスナップショットとネットワーク、コンソールを時間軸で確認できる画面です。テストを書きながら確かめる段階ではこれが最も速く回ります。
# UIモードで開く(テストを選んで実行・ステップを巻き戻して確認)
npx playwright test --ui
# インスペクタで1ステップずつ止めながら実行する
npx playwright test tests/login.spec.ts --debug
# 毎回トレースを取って、落ちたテストの記録を開く
npx playwright test --trace on
npx playwright show-trace test-results/<テストごとのフォルダ>/trace.zip
CIで落ちた場合は手元で再現しないこともあります。設定の trace: 'on-first-retry' により、再試行した回のトレースがレポートに添付されるので、成果物をダウンロードして同じ画面を開けます。トレースのディレクトリ名はテスト名とプロジェクト名から自動で付くため、実際のパスはレポートから辿ってください。
同じ実行・デバッグ・トレース確認をVS Codeの拡張から行う方法はPlaywright VS Code拡張の使い方:テスト実行・デバッグ・Pick locatorと録画の手順【1.65対応】で解説しています。
ログイン状態をsetupプロジェクトで保存して認証後の画面をテストする
認証後の画面を検証するたびにログイン操作を書くと、テストが遅くなり、ログイン画面の変更で全件が落ちます。公式のAuthenticationページが推奨するのは、ログインをsetup用のプロジェクトで1回だけ行い、Cookieとストレージをファイルに保存して各テストで読み込む方式です。
auth.setup.tsのstorageState保存とdependencies設定
// tests/auth.setup.ts
import { test as setup, expect } from '@playwright/test';
import path from 'path';
const authFile = path.join(__dirname, '../playwright/.auth/user.json');
setup('authenticate', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('メールアドレス').fill(process.env.E2E_USER ?? '');
await page.getByLabel('パスワード').fill(process.env.E2E_PASSWORD ?? '');
await page.getByRole('button', { name: 'ログイン' }).click();
await expect(page).toHaveURL(/\/dashboard/);
await page.context().storageState({ path: authFile });
});
// playwright.config.ts の projects を差し替える
projects: [
{ name: 'setup', testMatch: /.*\.setup\.ts/ },
{
name: 'chromium',
use: { ...devices['Desktop Chrome'], storageState: 'playwright/.auth/user.json' },
dependencies: ['setup'],
},
],
chromium プロジェクトは setup の完了後に動き、どのテストもログイン済みの状態から始まります。保存の前に toHaveURL で遷移を確かめているのは、リダイレクトの途中でCookieが確定する前に保存してしまう事故を避けるためです。
認証状態のファイルをGitに含めずテスト用アカウントを分ける注意点
保存されたJSONにはセッションCookieがそのまま入るため、公式ドキュメントはプライベートリポジトリであってもコミットしないよう強く求めています。初期化の直後に除外設定を入れておきます。
mkdir -p playwright/.auth
echo "playwright/.auth" >> .gitignore
もう一つの落とし穴はアカウントの共有です。1つのアカウントで並列に動かすと、設定を書き換えるテストが別のテストの前提を崩します。閲覧だけのテストは共有アカウントで足りますが、プロフィール更新や注文のようにサーバー側の状態を変えるテストは、ワーカーごとに別アカウントを割り当てる構成に切り替えてください。
GitHub Actionsで自動実行してHTMLレポートを成果物として残す設定
手元で通るだけでは、誰かの変更で壊れたことに気づけません。初期化時に GitHub Actions を選ぶと、push とプルリクエストでテストを流すワークフローが .github/workflows/playwright.yml に生成されます。
生成されたワークフローの構成と失敗時もレポートを保存する条件
公式のSetting up CIページのワークフローは、checkout と setup-node(Node.jsはLTS指定)、npm ci、npx playwright install --with-deps、テスト実行、レポートのアップロードという並びです。要点は、テストが落ちてもレポートを残すアップロードの条件にあります。
name: Playwright Tests
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: lts/*
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test
env:
E2E_USER: ${{ secrets.E2E_USER }}
E2E_PASSWORD: ${{ secrets.E2E_PASSWORD }}
- uses: actions/upload-artifact@v5
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 30
if: ${{ !cancelled() }} を外すと、テストが失敗した回ほどレポートが残らなくなります。認証情報は env の行のようにリポジトリのSecretsから渡し、ワークフローに直接書かないでください。ブラウザ導入の待ち時間を削る指定やシャード分割は、CLI一覧の記事で扱っています。
ランナーへ直接ブラウザを入れる代わりに、公式イメージを container に指定して同じ環境でテストを回す構成は、Playwright Docker実行ガイド:公式イメージでのテストとCI組み込み・詰まり所で手順とコード例を示しています。
CIだけ再試行とワーカー数を変える設定値と既定タイムアウトの扱い
先に示した設定では、process.env.CI を見て、CIでは再試行2回・ワーカー1、手元では再試行0に切り替えています。手元で再試行を0にしておくのは、不安定なテストを開発中に隠さないためです。forbidOnly は test.only の消し忘れをCIで失敗させる指定で、1本だけ流して全体が通ったと誤解する事故を防ぎます。
ジョブ単位のタイムアウトを置かない代わりに、公式は globalTimeout で実行全体に上限を設ける形を示しています。既定では全体の上限が無いため、ハングしたテストがCIの実行枠を食い続けないよう、テスト本数に応じた値を設定しておきます。
受託開発でPlaywrightのE2Eテストを入れる範囲と見送る条件の線引き
使い方を覚えると、すべての画面にE2Eテストを書きたくなります。ただE2Eは単体テストより実行に時間がかかり、画面変更のたびに保守が必要です。どこまで書くかを先に決めておかないと、テストの修正が開発の足を引っ張る状態に陥ります。
最初に自動化する対象は売上と認証に直結する5本前後の主要導線
最初の対象は、壊れたら売上か問い合わせが止まる導線に限ります。具体的にはログイン、会員登録、購入または申し込み、問い合わせ送信、パスワード再設定の5本前後です。入力値の組み合わせや表示崩れの網羅は単体テストやコンポーネントテストの領分で、E2Eで抱えると実行時間が伸びるだけです。配分の考え方はテストピラミッドとは?単体・結合・E2Eの配分と実装者向けテスト戦略設計で説明しています。
主要導線のテストがCIで毎回通り、失敗したときに誰がトレースを見るかが決まった時点で、本数を増やしてかまいません。テストを書く工数より、落ちたテストを直す運用が回るかどうかが分かれ目です。CIの構成から運用の引き継ぎまで外部と進める場合は、DevOps・CI/CD導入支援のように、パイプライン設計とテスト自動化をまとめて扱える体制と組むと、テストが放置される事態を避けられます。
画面仕様が週単位で変わる段階や見た目の確認が主目的ならE2Eは後回し
次のどれかに当てはまるなら、E2Eテストの導入は見送ってよい段階です。1つ目は、プロトタイプ段階で画面構成が週単位で変わるとき。書いたテストが翌週には合わなくなり、直す工数が検証の効果を上回ります。2つ目は、確かめたいのが配色や余白など見た目の差分であるとき。この目的ならスクリーンショット比較やアクセシビリティツリーの比較のほうが向いており、後者はPlaywright aria snapshotの使い方で手順を扱っています。3つ目は、テストを流すCI環境がまだ無いとき。手元でしか動かないE2Eは、数か月で誰も実行しなくなります。
よくある質問
Playwrightの使い方について、書き始めの段階でよく出る疑問をまとめました。
PlaywrightはJavaScriptとTypeScriptのどちらで書けばよいですか?
初期化コマンドの既定はTypeScriptで、公式ドキュメントのサンプルもTypeScriptが中心です。型によってロケーターやマッチャーの補完が効き、引数の誤りに実行前に気づけるため、特別な理由がなければTypeScriptを選んでください。トランスパイルの設定はPlaywright側で済むので、tsconfigを用意しなくてもテストは動きます。
PythonやJavaでもPlaywrightのテストは書けますか?
書けます。PlaywrightはNode.jsのほかPython・Java・.NET向けにも提供されています。ただしこの記事で扱った設定ファイル、setupプロジェクト、UIモードなどはNode.js向けのテストランナーである Playwright Test の機能です。Pythonではpytestと組み合わせる形になり、設定の書き方が変わります。Pythonでの導入手順はインストール方法の記事で触れています。
テストが不安定でたまに落ちるときはどこから疑えばよいですか?
まず固定秒数の待機と、取り出した値を同期的に比べる検証が残っていないかを確認します。次に、テスト同士が同じアカウントやデータを共有していないかを見ます。原因の特定には、--repeat-each で同じテストを繰り返して再現率を測り、落ちた回のトレースで直前のネットワークと画面を確かめる方法が早道です。
Playwright Testの最新版はいくつで、更新はどう行いますか?
2026年11月時点の公式リリースノートでは1.65系が最新で、テストランナーをBunで動かす対応や、失敗したテストだけを載せるレポートの指定が追加されています。更新は npm install -D @playwright/test@latest の後に npx playwright install --with-deps でブラウザも入れ直します。版の確かめ方はPlaywrightの最新バージョンの確認・更新方法を参照してください。
E2Eテストは何本くらいから書き始めればよいですか?
主要導線の5本前後で始め、まず優先するのはCIで毎回通る状態を作ることです。本数を一度に増やすと、失敗したときに直す人が追いつかず、テストが無視されるようになります。E2Eテスト全体の設計の考え方や結合テストとの違いはE2Eテストとは?結合テストとの違いとベストプラクティスで解説しています。
関連記事
- Playwright(プレイライト)とは?仕組み・できること・Seleniumとの違いを解説:本記事の前提となるPlaywrightの仕組みと他ツールとの違い
- Playwrightのインストール方法とできない時の対処|バージョン確認・Windows・Python:初期化やブラウザ導入で止まったときの切り分け
- Playwright CLIコマンド一覧|test・codegen・installと1.63の新オプション:実行の絞り込み・codegen・シャード分割などオプションの全体像
- Page Object Model(POM)とは?Playwright・Seleniumの実装例と保守コストの実測:テストが増えた後に保守しやすい形へ組み直す設計
- E2Eテストとは?結合テストとの違いとエンドツーエンドテストのベストプラクティス:どの導線をE2Eで守るかを決めるための考え方