Playwright vs Cypress — ブラウザテスト自動化ツール徹底比較
1. 結論
E2Eテストの信頼性・クロスブラウザ対応・CI環境での安定性を重視するなら Playwright を選んでください。フロントエンド開発者がインタラクティブなデバッグ体験と素早いフィードバックループを重視するなら Cypress が適しています。プロジェクトの規模が大きくなるほど、Playwright の優位性が際立つ傾向にあります。
2. 比較表
| 観点 | Playwright | Cypress |
|---|---|---|
| 開発元 | Microsoft | Cypress.io (現 Cypress) |
| 初回リリース | 2020年 | 2017年 |
| npm 週間DL数(2025年時点) | 約 1,000万+ | 約 500万+ |
| 対応ブラウザ | Chromium, Firefox, WebKit (Safari) | Chrome, Edge, Firefox, WebKit (実験的) |
| 言語サポート | TypeScript, JavaScript, Python, Java, C# | TypeScript, JavaScript |
| テスト実行モデル | ブラウザ外部からCDP/プロトコル経由で制御 | ブラウザ内部でテストコードが実行される |
| 並列実行 | ネイティブ対応(ワーカー数指定) | Cypress Cloud(有料)または外部ツール |
| 自動待機 (Auto-wait) | 組み込み(アクション単位で自動待機) | 組み込み(コマンドチェーンで自動リトライ) |
| ネットワーク制御 | route API で柔軟にインターセプト | cy.intercept で柔軟にインターセプト |
| iFrame対応 | ネイティブ対応 | プラグインが必要(制限あり) |
| マルチタブ対応 | ネイティブ対応 | 非対応 |
| ファイルダウンロード | ネイティブ対応 | ワークアラウンドが必要 |
| コンポーネントテスト | 実験的サポート | 公式サポート(React, Vue等) |
| TypeScript対応 | ファーストクラス | 公式サポート(設定が必要) |
| バンドルサイズ(node_modules) | 約 80MB(ブラウザ別途DL) | 約 300MB+ |
| テストランナーUI | HTML Reporter / Trace Viewer | Cypress App(インタラクティブGUI) |
| 学習コスト | 中程度(async/await ベース) | 低〜中(独自チェーンAPI) |
| CI/CD 親和性 | 非常に高い(Docker公式イメージあり) | 高い(Docker公式イメージあり) |
| ライセンス | Apache 2.0 | MIT |
| 有料プラン | なし(完全OSS) | Cypress Cloud(録画・並列・分析) |
3. それぞれの強み
Playwright の強み
真のクロスブラウザテスト
Playwright は Chromium・Firefox・WebKit の3エンジンをネイティブにサポートしています。特に WebKit(Safari相当) を Linux/Windows 上でもテストできる点は、macOS 環境がないCI環境では大きなメリットです。
マルチタブ・マルチコンテキスト
OAuth認証のポップアップや、新しいタブで開くリンクなど、複数タブ・複数ブラウザコンテキストを1つのテスト内で自然に扱えます。
並列実行がネイティブ
追加の有料サービスなしに、--workers オプションだけでテストを並列実行できます。大規模プロジェクトでのCI時間短縮に直結します。
Trace Viewer
テスト失敗時に スクリーンショット・DOMスナップショット・ネットワークログ・コンソールログ をタイムライン形式で確認できる Trace Viewer は、デバッグ体験として非常に強力です。
多言語対応
JavaScript/TypeScript だけでなく、Python・Java・C# でもテストを記述できるため、バックエンドチームとの協業がしやすくなります。
Cypress の強み
直感的なインタラクティブGUI
Cypress App はテスト実行中のブラウザをリアルタイムで確認でき、各コマンドのスナップショットをタイムトラベルで遡れます。フロントエンド開発者にとって、この即座のフィードバックは非常に魅力的です。
独自のコマンドチェーンAPI
cy.get().click().should() のようなチェーン記法は、Promise や async/await を意識せずに書けるため、非同期処理に不慣れな開発者でも直感的に記述できます。
コンポーネントテストの成熟度
React・Vue・Angular・Svelte などのコンポーネントをブラウザ上で単体テストできる機能が公式にサポートされており、Storybook 的な使い方も可能です。
豊富なプラグインエコシステム
長い歴史の中で蓄積されたサードパーティプラグインが豊富です。cypress-testing-library、cypress-axe(アクセシビリティ)、cypress-real-events など、実践的なプラグインが揃っています。
Cypress Cloud による分析
有料ではありますが、テスト結果のダッシュボード、フレーキーテストの検出、並列実行の最適化など、チーム開発を支援する機能が充実しています。
4. コード例で比較
以下では「TODOアプリにタスクを追加し、完了にして、フィルタリングする」という同じシナリオを両方で実装します。
Playwright(TypeScript)
// tests/todo.spec.ts
import { test, expect } from '@playwright/test';
test.describe('TODOアプリ', () => {
test.beforeEach(async ({ page }) => {
await page.goto('https://demo.playwright.dev/todomvc/');
});
test('タスクを追加し、完了にしてフィルタリングできる', async ({ page }) => {
// タスクを追加
const input = page.getByPlaceholder('What needs to be done?');
await input.fill('牛乳を買う');
await input.press('Enter');
await input.fill('レポートを書く');
await input.press('Enter');
// タスクが2件表示されていることを確認
const todoItems = page.getByTestId('todo-item');
await expect(todoItems).toHaveCount(2);
// 1件目を完了にする
const firstTodo = todoItems.nth(0);
await firstTodo.getByRole('checkbox').check();
// 「Active」フィルタをクリック
await page.getByRole('link', { name: 'Active' }).click();
// 未完了のタスクのみ表示される
await expect(todoItems).toHaveCount(1);
await expect(todoItems.nth(0)).toContainText('レポートを書く');
// 「Completed」フィルタをクリック
await page.getByRole('link', { name: 'Completed' }).click();
// 完了済みのタスクのみ表示される
await expect(todoItems).toHaveCount(1);
await expect(todoItems.nth(0)).toContainText('牛乳を買う');
});
});
Cypress(TypeScript)
// cypress/e2e/todo.cy.ts
describe('TODOアプリ', () => {
beforeEach(() => {
cy.visit('https://demo.playwright.dev/todomvc/');
});
it('タスクを追加し、完了にしてフィルタリングできる', () => {
// タスクを追加
cy.get('[placeholder="What needs to be done?"]')
.type('牛乳を買う{enter}')
.type('レポートを書く{enter}');
// タスクが2件表示されていることを確認
cy.get('[data-testid="todo-item"]')
.should('have.length', 2);
// 1件目を完了にする
cy.get('[data-testid="todo-item"]')
.first()
.find('input[type="checkbox"]')
.check();
// 「Active」フィルタをクリック
cy.contains('a', 'Active').click();
// 未完了のタスクのみ表示される
cy.get('[data-testid="todo-item"]')
.should('have.length', 1)
.first()
.should('contain.text', 'レポートを書く');
// 「Completed」フィルタをクリック
cy.contains('a', 'Completed').click();
// 完了済みのタスクのみ表示される
cy.get('[data-testid="todo-item"]')
.should('have.length', 1)
.first()
.should('contain.text', '牛乳を買う');
});
});
コード比較のポイント
| 観点 | Playwright | Cypress |
|---|---|---|
| 非同期処理 | async/await で明示的に制御 | 内部キューで自動管理(await 不要) |
| 要素の取得 | getByRole, getByTestId 等のロケーター | cy.get() + CSSセレクタが基本 |
| アサーション | expect() + マッチャー(Jest風) | .should() チェーン(Chai風) |
| 可読性 | JavaScript の標準的な書き方に近い | 独自DSLだが簡潔 |
5. どちらを選ぶべきか — ユースケース別の推奨
✅ Playwright を選ぶべきケース
| ユースケース | 理由 |
|---|---|
| クロスブラウザテストが必須 | Safari (WebKit) を含む3エンジンをネイティブサポート |
| 大規模プロジェクトのCI/CD | ネイティブ並列実行で追加コストなし |
| マルチタブ・ポップアップのテスト | OAuth認証フローなどを自然に記述可能 |
| API テストも統合したい | request コンテキストで API テストも記述可能 |
| 多言語チーム | Python / Java / C# チームとも共有可能 |
| 完全OSSで運用したい | 有料機能への依存がない |
✅ Cypress を選ぶべきケース
| ユースケース | 理由 |
|---|---|
| フロントエンド中心の小〜中規模プロジェクト | GUI のデバッグ体験が開発速度を加速 |
| コンポーネントテストを重視 | React / Vue 等のコンポーネントテストが成熟 |
| チームに E2E テスト初心者が多い | チェーンAPIの学習コストが低い |
| 既存の Cypress 資産がある | 移行コストを考慮すると継続が合理的 |
| Cypress Cloud の分析機能を活用したい | フレーキーテスト検出・テスト分析が強力 |
⚠️ 判断に迷ったら
2025年現在のトレンドとしては、新規プロジェクトでは Playwright を選択するケースが増えています。npm ダウンロード数の伸び率、State of JS 調査での満足度、GitHub スター数の推移いずれも Playwright が上昇傾向にあります。ただし、Cypress が劣っているわけではなく、特にフロントエンド開発者のDX(開発者体験)においては依然として高い評価を得ています。
6. まとめ
Playwright = 「テストインフラとしての堅牢性」を追求するツール
Cypress = 「開発者のテスト体験」を追求するツール
両者はブラウザテスト自動化という同じ領域のツールですが、設計思想が根本的に異なります。Playwright はブラウザの外側からプロトコル経由で制御するアーキテクチャにより、マルチタブ・マルチブラウザ・並列実行といった「テストインフラとしての柔軟性」に優れています。一方 Cypress はブラウザ内部でテストを実行するアーキテクチャにより、リアルタイムのタイムトラベルデバッグや直感的なAPIといった「開発者体験」に優れています。
最終的には、チームのスキルセット・プロジェクトの規模・テスト戦略を総合的に判断して選択してください。どちらを選んでも、手動テストからの脱却という点では大きな前進になるはずです。