playwright、puppeteer、selenium-webdriver はすべてブラウザの自動操作を可能にするnpmパッケージであり、主にエンドツーエンド(E2E)テストやスクレイピング、自動化タスクに使われます。これらはそれぞれ異なるアプローチでブラウザ制御を実現しており、サポートするブラウザ範囲、API設計、安定性、デバッグ機能などに明確な違いがあります。
フロントエンド開発者がE2Eテストやブラウザ自動化を実装する際、playwright、puppeteer、selenium-webdriver の3つが代表的な選択肢になります。これらは目的こそ似ていますが、設計思想や実装方法、サポート範囲に大きな違いがあります。現場で実際に使う観点から、深く掘り下げて比較します。
puppeteer は Chromium系のみ をサポートします。つまり、ChromeやMicrosoft Edge(Chromium版)は動作しますが、FirefoxやSafariは対象外です。
// puppeteer: Chromium系限定
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
playwright は Chromium、Firefox、WebKit(Safariのエンジン)の3つを公式サポート しています。1つのテストコードで複数ブラウザでの動作確認が可能です。
// playwright: ブラウザごとに起動可能
const { chromium, firefox, webkit } = require('playwright');
const browser = await chromium.launch(); // または firefox.launch(), webkit.launch()
const page = await browser.newPage();
await page.goto('https://example.com');
selenium-webdriver は理論上 すべてのWebDriver準拠ブラウザ をサポートしますが、各ブラウザ用のドライバー(chromedriver、geckodriverなど)を別途インストール・管理する必要があります。
// selenium-webdriver: ドライバー依存
const { Builder, By } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
let driver = await new Builder()
.forBrowser('chrome')
.setChromeOptions(new chrome.Options())
.build();
await driver.get('https://example.com');
💡 実務では、FirefoxやSafariでの動作検証が必要なら
playwright一択。Chromium系だけで十分ならpuppeteerの軽さが魅力。レガシー環境やマルチ言語対応が必須ならselenium-webdriverを検討。
puppeteer と playwright はどちらもモダンで一貫性のあるPromiseベースのAPIを持ち、page.click() や page.fill() のように直感的に操作できます。
// puppeteer
await page.goto('https://example.com');
await page.type('#username', 'testuser');
await page.click('#submit');
// playwright
await page.goto('https://example.com');
await page.fill('#username', 'testuser');
await page.click('#submit');
一方、selenium-webdriver はWebDriverプロトコルに忠実なため、要素の取得と操作が分かれており、コードが冗長になりがちです。
// selenium-webdriver
await driver.get('https://example.com');
let username = await driver.findElement(By.id('username'));
await username.sendKeys('testuser');
let submit = await driver.findElement(By.id('submit'));
await submit.click();
また、selenium-webdriver は非同期処理を async/await で書くこともできますが、内部でコマンドキューを管理するため、エラーハンドリングやデバッグがやや複雑です。
不安定なE2Eテストの最大の原因は「タイミング」です。各ツールはこの問題に対し、異なるアプローチを取っています。
puppeteer は page.waitForSelector() や page.waitForFunction() を使って明示的に待機する必要があります。
// puppeteer: 手動待機
await page.click('#load-data');
await page.waitForSelector('#result'); // 要素が表示されるまで待つ
playwright は多くのアクション(click、fill など)に 自動待機機能 が組み込まれており、要素が操作可能になるまで内部で待機します。
// playwright: 自動待機
await page.click('#load-data');
await page.click('#result'); // 要素がクリック可能になるまで自動で待つ
selenium-webdriver は WebDriverWait のような明示的待機(Explicit Wait)を推奨しており、Implicit Wait(暗黙的待機)は非推奨です。
// selenium-webdriver: 明示的待機
const until = require('selenium-webdriver/until');
await driver.findElement(By.id('load-data')).click();
await driver.wait(until.elementLocated(By.id('result')), 5000);
💡 実務では、
playwrightの自動待機がテストの安定性を大幅に向上させ、メンテナンスコストを削減します。puppeteerやselenium-webdriverでは待機ロジックの記述漏れがバグの温床になりやすいです。
モバイル端末や低速ネットワーク下での動作確認が必要な場合、ツール間でサポート状況が大きく異なります。
playwright はビルドインで デバイスエミュレーション と ネットワークスロットリング をサポートしています。
// playwright: デバイスエミュレーション
const { devices } = require('playwright');
const iPhone = devices['iPhone 13'];
const context = await browser.newContext({ ...iPhone });
const page = await context.newPage();
// playwright: ネットワーク制限
await context.setOffline(true);
await context.setGeolocation({ latitude: 35.6895, longitude: 139.6917 });
puppeteer もChromiumの機能を活用して同様のことが可能ですが、設定がやや低レベルです。
// puppeteer: ネットワーク制限
const client = await page.target().createCDPSession();
await client.send('Network.emulateNetworkConditions', {
offline: false,
latency: 100,
downloadThroughput: 1.5 * 1024 * 1024 / 8,
uploadThroughput: 1.5 * 1024 * 1024 / 8
});
selenium-webdriver は標準ではこれらの機能を提供せず、ブラウザ固有の拡張(例:Chrome DevTools Protocol経由)を使う必要があります。そのため、設定が複雑でポータビリティが低いです。
playwright は PWDEBUG=1 環境変数でGUI付きデバッガーを起動でき、タイムトラベルデバッグやスクリーンショット比較も可能です。
PWDEBUG=1 npm test
puppeteer は headless: false オプションでブラウザを可視化できますが、高度なデバッグ機能は備えていません。
// puppeteer: 可視化
const browser = await puppeteer.launch({ headless: false });
selenium-webdriver も同様にヘッドフルモードで実行可能ですが、デバッグ支援機能は最小限です。
puppeteer と playwright は npm install 時に必要なブラウザバイナリを自動でダウンロードします。追加設定不要で即座に使い始められます。
npm install playwright
# → Chromium, Firefox, WebKit が自動インストール
selenium-webdriver はブラウザドライバーを別途管理する必要があります。たとえばChromeを使うには chromedriver をインストールし、PATHを通すか、コード内でパスを指定する必要があります。
// selenium-webdriver: ドライバーの明示的指定
const service = new chrome.ServiceBuilder('/path/to/chromedriver').build();
chrome.setDefaultService(service);
これはCI環境でのセットアップを煩雑にし、チーム内での環境差異を生む原因になります。
2024年現在、いずれのパッケージも 非推奨ではありません。puppeteer はGoogleが、playwright はMicrosoftが、selenium-webdriver はSeleniumプロジェクトがそれぞれ積極的にメンテナンスしています。
ただし、puppeteer は2023年にコミュニティ主導のプロジェクトとなり、Googleによる直接的な開発は終了しました。一方、playwright は活発な開発が続いており、新機能(例:Component Testing、Trace Viewer)が継続的に追加されています。
| 観点 | playwright | puppeteer | selenium-webdriver |
|---|---|---|---|
| サポートブラウザ | Chromium, Firefox, WebKit | Chromium系のみ | 全WebDriver準拠ブラウザ(ドライバー要) |
| APIの使いやすさ | 非常に直感的(自動待機付き) | 直感的だが手動待機必要 | 冗長(要素取得と操作が分離) |
| モバイル/ネットワークエミュレート | ビルドインで簡単 | 可能だが低レベル | 標準では不可、ブラウザ依存 |
| デバッグ支援 | GUIデバッガー、トレース機能 | ヘッドフルモードのみ | 最小限 |
| セットアップの手間 | 自動(npm installで完了) | 自動 | ドライバー管理が必要 |
| 最適なユースケース | 本格的なE2Eテスト、クロスブラウザ検証 | スクレイピング、Chromium限定の自動化 | マルチ言語環境、既存Seleniumインフラとの統合 |
playwright を試すべきです。安定性、機能、開発体験のすべてで現代的なニーズに応えています。puppeteer も有効。特にスクレイピングやPDF生成など、テスト以外の自動化タスクに向いています。selenium-webdriver は、既にSeleniumエコシステムに投資している組織や、複数言語でテストを統一したい場合に限って検討してください。純粋なNode.jsプロジェクトではオーバーヘッドが大きすぎます。これらのツールは「どれが絶対に優れている」というより、「どんな課題を解決したいか」によって最適解が変わります。あなたのチームの技術スタック、テスト要件、保守コストを見極めて、賢く選んでください。
puppeteer を選ぶべきなのは、Chromium系ブラウザ(ChromeやEdge)のみを対象とし、シンプルで軽量な自動化スクリプトやスクレイピングを実装したい場合です。Playwrightほどの多機能さは不要で、既存のNode.js環境に手軽に組み込みたいケースに向いています。
playwright を選ぶべきなのは、複数のブラウザ(Chromium、Firefox、WebKit)でのテストが必要な場合、または最新のWeb標準やモバイルエミュレーション、ネットワーク条件のシミュレーションといった高度な機能を活用したいときです。特に大規模なE2EテストスイートやCI/CD環境での安定した実行を求めるプロジェクトに適しています。
selenium-webdriver を選ぶべきなのは、JavaやPythonなど複数の言語環境で同じテストコードを共有したい場合、あるいは既にSelenium Gridなどのインフラを運用している組織において、JavaScriptベースのテストも統合したいときです。ただし、Node.js専用のユースケースでは他の2つより冗長になることが多いです。
Puppeteer is a JavaScript library which provides a high-level API to control Chrome or Firefox over the DevTools Protocol or WebDriver BiDi. Puppeteer runs in the headless (no visible UI) by default
npm i puppeteer # Downloads compatible Chrome during installation.
npm i puppeteer-core # Alternatively, install as a library, without downloading Chrome.
Install chrome-devtools-mcp,
a Puppeteer-based MCP server for browser automation and debugging.
import puppeteer from 'puppeteer';
// Or import puppeteer from 'puppeteer-core';
// Launch the browser and open a new blank page.
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Navigate the page to a URL.
await page.goto('https://developer.chrome.com/');
// Set screen size.
await page.setViewport({width: 1080, height: 1024});
// Open the search menu using the keyboard.
await page.keyboard.press('/');
// Type into search box using accessible input name.
await page.locator('::-p-aria(Search)').fill('automate beyond recorder');
// Wait and click on first result.
await page.locator('.devsite-result-item-link').click();
// Locate the full title with a unique string.
const textSelector = await page
.locator('::-p-text(Customize and automate)')
.waitHandle();
const fullTitle = await textSelector?.evaluate(el => el.textContent);
// Print the full title.
console.log('The title of this blog post is "%s".', fullTitle);
await browser.close();