PlaywrightでE2Eテスト入門|導入から壊れにくい書き方・CI設定まで
PlaywrightはMicrosoftが開発するオープンソースのE2Eテストフレームワークで、ブラウザ上でのユーザー操作を自動再現し、アプリケーション全体の動作を検証できます。Chromium・Firefox・WebKitの3エンジンに標準対応し、自動待機(Auto-waiting)やテストコード自動生成(Codegen)など、実務に必要な機能を無料で利用できます。
本記事では、Playwrightの特徴とCypressやSeleniumとの違いから、E2Eテスト導入に必要な一連の流れを扱います。「導入はできたが保守で詰まる」という状況を避けながら、テストが開発フローに定着するまでの道筋を自分で判断できることを目指します。
もし「TypeScriptでのコーディングがチーム全体の障壁になる」という懸念があるなら、T-DASHの導入が有効です。T-DASHは日本語のテストケースで自動化が可能なため、エンジニアに依存せず、QAメンバー自身が中心となってテスト作成を進められます。技術的な制約を超えてチーム一丸となって自動化を推進したい方は、ぜひT-DASH公式サイトで詳細をご覧ください。
PlaywrightのE2Eテストとは? ツールの特徴と選ばれる理由

E2Eテストとは何か、そしてなぜ今Playwrightが選ばれるのかを理解しておくと、後続の導入手順や書き方の原則がより明確に見えてきます。
まずE2Eテストの定義と役割を整理し、Playwrightの特徴、そしてCypressやSeleniumとの違いへと順に展開します。
E2Eテストの役割とテスト戦略での位置づけ
E2Eテスト(End-to-Endテスト)は、ユーザーの実操作をブラウザ上で自動再現し、アプリケーション全体の動作を検証するテスト手法です。
ボタンをクリックしてモーダルが表示される、フォームを入力して画面が遷移する、といったUI挙動を含む一連のシナリオをそのまま自動化します。
ユニットテストが関数やロジック単位の正しさを確認するのに対し、E2Eテストはそれらが連携した結果としてユーザーに届く体験全体を検証します。実行コストと保守コストが高いため、全シナリオを網羅せず、ログインや購入といった重要シナリオに絞るのが定石です。
Playwrightの主な特徴
こうした位置づけのE2Eテストを実務で支えるのがPlaywrightです。PlaywrightはMicrosoftが開発するオープンソースのE2Eテストフレームワークで、2020年の公開以降、急速にスタンダードの地位を固めています。
Chromium・Firefox・WebKitの3エンジンを単一のAPIで操作できる点が最大の設計上の特徴で、ブラウザごとに別のツールセットを用意する必要がありません。
Playwrightの主な機能は次のとおりです。
- マルチブラウザ対応(Chromium・Firefox・WebKit):Chrome・Edge・Firefox・Safari相当を同じテストコードで検証でき、「Chromeでは動くがSafariで崩れる」をコードの書き直しなしに確認できます。
- 自動待機(Auto-waiting):DOM要素の表示・操作可能・アニメーション完了などを自動で待ってから操作するため、固定秒数のwaitForTimeoutに頼らず安定します。
- 高速な並列実行:ビルトインのsharding機能でCI上の並列実行を追加コストなしに実現し、テストが増えても実行時間を抑えられます。
- 補助機能:操作を記録してコードを自動生成するCodegen、失敗時の実行経路を可視化するトレースビューアも標準装備です。
CypressやSeleniumとの違い
ツール選定の判断軸を明確にするため、Playwright・Cypress・Seleniumの3つを比較します。各ツールの位置づけは以下のとおりです。
| ツール | CI並列実行 | 対応ブラウザ |
|---|---|---|
| Playwright | ビルトインsharding(無料) | Chromium・Firefox・WebKit |
| Cypress | Cypress Cloud(SaaS契約が必要) | Chrome系・Firefox(WebKitは実験的) |
| Selenium | 外部ツール依存 | WebDriver経由で広範に対応 |
表からわかるとおり、3ツールはブラウザ自動化という同じ目的を担いつつ、CI並列実行の手軽さと対応ブラウザの広さで性格が分かれます。Seleniumは対応範囲が最も広い一方でCI並列化は外部ツールに依存し、Cypressはデバッグのしやすさに強みがある半面、対応ブラウザは限定的です。
Playwrightは追加コストのかからない並列実行と主要3エンジンへの標準対応を両立しており、本記事ではこのPlaywrightを軸に導入手順を解説します。
Playwrightの始め方(インストールから初回テスト実行まで)

選定の根拠が見えたところで、実際に手を動かしてみましょう。
Playwrightはnpm init playwright@latestの1コマンドで、設定ファイル・サンプルテスト・テスト用ブラウザまで一括でセットアップできます。既存のVite + TypeScriptプロジェクトに追加する場合も、同じコマンドで数分以内に動く状態にたどり着けます。
この章では、コマンドの実行から最初のテストが通るまでを3ステップで追います。各ステップで生成・編集するファイルの関係を把握しながら進めてください。
- パッケージのインストールとブラウザの準備
- playwright.config.tsの基本設定
- 最初のテストを書いて実行する
1. パッケージのインストールとブラウザの準備
プロジェクトのルートディレクトリで次のコマンドを実行します。
npm init playwright@latest
実行すると対話形式のセットアップが始まります。
- テストファイルの配置先(デフォルト: tests): Enterでそのまま確定します。Vite + TypeScriptプロジェクトではsrcと並ぶtestsディレクトリが一般的です。
- GitHub Actions ワークフローの追加: CIを後から設定する場合はnでスキップして問題ありません。
- ブラウザのインストール: yを選択します。Chromium・Firefox・WebKitの3ブラウザが自動的にダウンロードされます。

セットアップが完了すると、プロジェクトのディレクトリ構成は次のようになります。
my-app/
├── tests/
│ └── example.spec.ts # サンプルテスト
├── playwright.config.ts # 設定ファイル
├── package.json
└── …(既存ファイル)
ブラウザは~/.cache/ms-playwright以下にインストールされ、ホストOSにインストールされているChromeなどとは独立して管理されます。ブラウザバージョンの差異がテスト結果に影響しないのはこのためです。
すでにpackage.jsonが存在するプロジェクトにパッケージだけを追加したい場合は、次の2コマンドでも同じ状態にたどり着けます。
npm install -D @playwright/test
npx playwright install
2. playwright.config.tsの基本設定
セットアップで生成されたplaywright.config.tsを、既存の開発サーバーと共存できる形に編集します。
最低限必要な設定はtestDir・webServer・projectsの3項目です。
import { defineConfig, devices } from ‘@playwright/test’;
export default defineConfig({
testDir: ‘./tests’,
webServer: {
command: ‘npm run dev’,
url: ‘http://localhost:5173’,
reuseExistingServer: !process.env.CI,
},
use: {
baseURL: ‘http://localhost:5173’,
headless: true,
},
projects: [
{ name: ‘chromium’, use: { …devices[‘Desktop Chrome’] } },
{ name: ‘firefox’, use: { …devices[‘Desktop Firefox’] } },
{ name: ‘webkit’, use: { …devices[‘Desktop Safari’] } },
],
});
このうちtestDirとprojectsの役割は次のとおりです。
- testDir:テストファイルを探すディレクトリ。Vitestなどのユニットテストとパスを分けておくと実行対象が混在しません。
- projects:実行対象ブラウザの定義。列挙した全ブラウザで同じテストが並列実行されます。
3. 最初のテストを書いて実行する
testsディレクトリにapp.spec.tsを作成し、最小構成のテストを書きます。ここではボタンをクリックしてテキストが変化することを検証するシンプルな例を使います。
import { test, expect } from ‘@playwright/test’;
test(‘カウンターのボタンをクリックすると数値が増える’, async ({ page }) => {
await page.goto(‘/’);
const button = page.getByRole(‘button’, { name: ‘count’ });
await button.click();
await expect(page.getByRole(‘button’, { name: ‘count is 1’ })).toBeVisible();
});
このコードには、Playwrightの基本APIが4つ登場します。test()でテストケースに名前をつけてブロックを定義します。page.goto(‘/’)はbaseURLからの相対パスでページに遷移します。

page.getByRole()はARIAロールとアクセシブルな名前で要素を取得するLocatorで、CSSセレクタの代わりにUIの意味で要素を特定します。expect().toBeVisible()はPlaywrightの自動待機機能を持つアサーションで、要素が表示されるまで一定時間待機してから成否を判定します。
テストを実行するコマンドは2種類あり、用途で使い分けます。
ヘッドレス実行(CI・通常確認用):
npx playwright test
ブラウザウィンドウを表示せずに全テストを実行します。結果はターミナルに出力され、失敗時はHTMLレポートが自動生成されます。
UIモード起動(デバッグ用):
npx playwright test –ui
ブラウザ上のGUIが起動し、テストをステップ単位で再生できます。各ステップのスクリーンショットが時系列で並ぶタイムライン表示から、どの操作で失敗したかを視覚的に確認できるため、テストが通らない原因の特定が速くなります。
初回実行後にtest-results/とplaywright-report/の2つのディレクトリが生成されます。これらはテスト成果物であってソースコードではないため、.gitignoreに追加しておくことをおすすめします。
テスト実行時の進捗管理とテストケースの管理を見える化したい方には、テスト自動化ツール「T-DASH」と連携できるテスト管理ツール「QualityTracker」がおすすめです。
▶ テスト管理なら「QualityTracker」
壊れにくいE2Eテストを書く3つの原則

最初のテストが通ったら、次に意識したいのが「壊れにくさ」です。
getByRole系Locator・web-first assertions・Codegenを組み合わせることで、UI変更や環境差に左右されにくいE2Eテストを実現できます。E2Eテストが壊れる原因は、CSSクラス名やDOM構造に依存したセレクタ、固定秒数の待機処理、そして手書きの冗長なテストコードという3つに絞れます。
この3つを解消する書き方の原則として、それぞれの手法を組み合わせることが有効です。
1. getByRoleでUI変更に強いLocatorを使う
getByRoleはHTML要素のアクセシビリティロールで要素を特定するため、クラス名やDOM構造が変わってもテストが壊れにくいLocatorです。
CSSセレクタを使ったpage.locator(‘.btn-primary’)のような書き方は、デザインリニューアルでクラス名が.button-submitに変わった瞬間、テストは実行すら通らなくなります。要素の意味は変わっていないのに、見た目の実装詳細に依存しているためです。
getByRoleが推奨される理由を整理すると、次の3点です。
- CSS・XPathのような実装詳細ではなく意味で要素を指定するため、リファクタリングやデザイン変更の影響を受けにくい
- ユーザーが「このボタンを押す」と認識するのと同じ粒度で要素を特定でき、テストが人間の操作に近い表現になる
- WAI-ARIAのロール・ラベルが正しく設定されていないと取得できないため、アクセシビリティの実装漏れを自然に検出できる
Playwright公式ドキュメントでもgetByRoleを優先Locatorとして位置づけており、セレクタ選定に迷ったときはまずgetByRoleで書けないかを確認してください(参考:Playwright公式ドキュメント Locators)。
2. web-first assertionsでFlaky testを防ぐ
テストが「手元では通るのにCIだと落ちる」という状況の多くは、次のような固定待機が原因です。
await page.waitForTimeout(5000);
await expect(page.getByRole(‘heading’, { name: ‘完了’ })).toBeVisible();
5秒待っても処理が終わらなければテストは落ち、逆に高速な環境では5秒も待つ必要がなく無駄な時間が生まれます。実行環境のマシンスペックやネットワーク速度の差がそのままテストの安定性に直結するため、CI環境でのFlaky testの温床になります。

これをweb-first assertionsで書き直すと、次のようになります。
await expect(page.getByRole(‘heading’, { name: ‘完了’ })).toBeVisible();
よく使うweb-first assertionsの代表例を挙げます。
- toBeVisible():要素が画面上に表示されているか
- toHaveText(‘テキスト’):要素が指定したテキストを持つか
- toBeEnabled():ボタンや入力欄が操作可能な状態か
3. Codegenでテストコードの出発点を自動生成する
ターミナルで次のコマンドを実行すると、Playwrightが専用のブラウザウィンドウを立ち上げ、操作を自動的にテストコードへ記録します。
npx playwright codegen http://localhost:5173
getByRoleやweb-first assertionsを使うべきだとわかっていても、初めてテストを書くときは「この要素はどのロールで取得すればいいのか」の判断に迷います。Codegenはこの迷いを解消するツールです。
ブラウザ上でクリックや文字入力を行うと、その操作がリアルタイムでテストコードとして別ウィンドウに記録されます。生成されるLocatorはgetByRole・getByLabel・getByPlaceholderなど、Playwrightが推奨する形式で自動的に選択されるため、セレクタ選定の判断をCodegenに任せることができます。
GitHub ActionsでCI実行する設定手順

壊れにくいテストが書けても、開発者のローカル環境でしか動かない状態では自動化の恩恵が限られます。push のたびに自動実行されるCI環境に組み込んではじめて、E2E テストは品質保証の仕組みとして機能します。
ここでは、ワークフローファイルを1つ追加するだけで Playwright のテストをゼロコストで自動実行できるGitHub Actionsを取り上げ、CIを構築する手順をご紹介します。
1. ワークフローファイルの作成
GitHub Actions のワークフローは、リポジトリ直下の .github/workflows/ ディレクトリに YAML ファイルを置くことで定義します。まず完成形のワークフローを示し、各ステップの意味を説明します。
# .github/workflows/playwright.yml
name: Playwright Tests
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
jobs:
test:
runs-on: ubuntu-latest
steps:
– uses: actions/checkout@v4
– uses: actions/setup-node@v4
with:
node-version: 20
cache: ‘npm’
– name: Install dependencies
run: npm ci
– name: Install Playwright browsers
run: npx playwright install –with-deps
– name: Run Playwright tests
run: npx playwright test
– name: Upload test report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
ステップの流れは次のとおりです。
- actions/checkout: リポジトリのコードをランナーにチェックアウトします。
- actions/setup-node: Node.js 20 を用意し、npm キャッシュを有効にして依存関係の取得を高速化します。
- npm ci: package-lock.json に固定されたバージョンで依存パッケージを再現インストールします。npm install ではなく npm CIを使うことで、環境間のバージョン差異を排除できます。
- playwright install –with-deps: Chromium・Firefox・WebKit の3ブラウザと、各ブラウザが動作するために必要な OS 依存ライブラリ(libglib・nss 等)を一括インストールします。後述しますが、このステップが CI環境では不可欠です。
- npx playwright test: playwright.config.ts の設定に従ってテストを実行します。
- upload-artifact: テスト結果の HTML レポートをアーティファクトとして保存します。if: always() を指定することで、テストが失敗した場合でもレポートがアップロードされます。
2. テスト結果の確認とリトライ設定
CIでテストが失敗したとき、原因を素早く特定できる体制を整えておくことが運用の継続につながります。Playwright のレポート機能とリトライ設定を組み合わせることで、失敗の原因調査とノイズの吸収を両立できます。
Playwright はテスト実行後に playwright-report/ ディレクトリへ HTML レポートを出力します。このレポートには失敗したテストのスクリーンショット・トレース・エラーメッセージが含まれており、ブラウザで開くだけで何が起きたかを視覚的に確認できます。
次に、CI環境特有のテスト不安定化への対処です。ローカルでは再現しないのに CIでだけ失敗するテストには、主にブラウザキャッシュなし・ネットワーク遅延・並列実行時のポート競合という3つのパターンがあります。これらは環境の差異に起因する一時的な失敗であり、テストコード自体の問題ではありません。
retries オプションを設定すると、失敗したテストを自動で再試行します。設定は playwright.config.ts で行うか、コマンドラインオプションで指定します。
// playwright.config.ts
export default defineConfig({
retries: process.env.CI? 2 : 0, // CI環境でのみ2回リトライ
reporter: [
[‘html’],
[‘list’],
],
});
テスト実行時の進捗管理とテストケースの管理を見える化したい方には、テスト自動化ツール「T-DASH」と連携できるテスト管理ツール「QualityTracker」がおすすめです。
▶ テスト管理なら「QualityTracker」
PlaywrightによるE2Eテスト導入のまとめ

Playwrightは、npm init playwright@latestの1コマンドで環境を整え、getByRoleとweb-first assertionsの原則に沿ってテストを書き、GitHub ActionsのワークフローファイルでCI実行まで組むことで、導入後も壊れにくいE2Eテストを低コストで運用し続けられます。
まずはChromiumの1ブラウザに絞って導入し、コアな正常系シナリオ(ログイン・フォーム送信・購入など)だけをカバーする小さなテストスイートをCIに乗せることを最初の一手として推奨します。
そこから安定稼働を確認しつつ、FirefoxとWebKitを追加し、カバーするシナリオを広げていくのが保守コストを抑えながら定着させる現実的な進め方です。
ただし、TypeScriptによるコーディング自体がチームの障壁になる場合には、別の選択肢もあります。テスト自動化にプログラミングの壁を感じるチームには、日本語で書いたテストケースがそのまま自動テストとして実行できるT-DASHが選択肢になります。コーディング経験のないQAメンバーも含めてチームでテスト自動化を進めたい場合は、T-DASH公式サイトから詳細を確認してみてください。
T-DASHでどこまで自動化できるかを試してみたい場合は、無料トライアルで実際の操作感を確認することもできます。
▶ 30日間無料で試してみる
