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プロジェクトではオーバーヘッドが大きすぎます。これらのツールは「どれが絶対に優れている」というより、「どんな課題を解決したいか」によって最適解が変わります。あなたのチームの技術スタック、テスト要件、保守コストを見極めて、賢く選んでください。
playwright を選ぶべきなのは、複数のブラウザ(Chromium、Firefox、WebKit)でのテストが必要な場合、または最新のWeb標準やモバイルエミュレーション、ネットワーク条件のシミュレーションといった高度な機能を活用したいときです。特に大規模なE2EテストスイートやCI/CD環境での安定した実行を求めるプロジェクトに適しています。
puppeteer を選ぶべきなのは、Chromium系ブラウザ(ChromeやEdge)のみを対象とし、シンプルで軽量な自動化スクリプトやスクレイピングを実装したい場合です。Playwrightほどの多機能さは不要で、既存のNode.js環境に手軽に組み込みたいケースに向いています。
selenium-webdriver を選ぶべきなのは、JavaやPythonなど複数の言語環境で同じテストコードを共有したい場合、あるいは既にSelenium Gridなどのインフラを運用している組織において、JavaScriptベースのテストも統合したいときです。ただし、Node.js専用のユースケースでは他の2つより冗長になることが多いです。
Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API. Playwright is built to enable cross-browser web automation that is ever-green, capable, reliable and fast.
| Linux | macOS | Windows | |
|---|---|---|---|
| Chromium 143.0.7499.4 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| WebKit 26.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Firefox 144.0.2 | :white_check_mark: | :white_check_mark: | :white_check_mark: |
Headless execution is supported for all browsers on all platforms. Check out system requirements for details.
Looking for Playwright for Python, .NET, or Java?
Playwright has its own test runner for end-to-end tests, we call it Playwright Test.
The easiest way to get started with Playwright Test is to run the init command.
# Run from your project's root directory
npm init playwright@latest
# Or create a new project
npm init playwright@latest new-project
This will create a configuration file, optionally add examples, a GitHub Action workflow and a first test example.spec.ts. You can now jump directly to writing assertions section.
Add dependency and install browsers.
npm i -D @playwright/test
# install supported browsers
npx playwright install
You can optionally install only selected browsers, see install browsers for more details. Or you can install no browsers at all and use existing browser channels.
Auto-wait. Playwright waits for elements to be actionable prior to performing actions. It also has a rich set of introspection events. The combination of the two eliminates the need for artificial timeouts - a primary cause of flaky tests.
Web-first assertions. Playwright assertions are created specifically for the dynamic web. Checks are automatically retried until the necessary conditions are met.
Tracing. Configure test retry strategy, capture execution trace, videos and screenshots to eliminate flakes.
Browsers run web content belonging to different origins in different processes. Playwright is aligned with the architecture of the modern browsers and runs tests out-of-process. This makes Playwright free of the typical in-process test runner limitations.
Multiple everything. Test scenarios that span multiple tabs, multiple origins and multiple users. Create scenarios with different contexts for different users and run them against your server, all in one test.
Trusted events. Hover elements, interact with dynamic controls and produce trusted events. Playwright uses real browser input pipeline indistinguishable from the real user.
Test frames, pierce Shadow DOM. Playwright selectors pierce shadow DOM and allow entering frames seamlessly.
Browser contexts. Playwright creates a browser context for each test. Browser context is equivalent to a brand new browser profile. This delivers full test isolation with zero overhead. Creating a new browser context only takes a handful of milliseconds.
Log in once. Save the authentication state of the context and reuse it in all the tests. This bypasses repetitive log-in operations in each test, yet delivers full isolation of independent tests.
Codegen. Generate tests by recording your actions. Save them into any language.
Playwright inspector. Inspect page, generate selectors, step through the test execution, see click points and explore execution logs.
Trace Viewer. Capture all the information to investigate the test failure. Playwright trace contains test execution screencast, live DOM snapshots, action explorer, test source and many more.
Looking for Playwright for TypeScript, JavaScript, Python, .NET, or Java?
To learn how to run these Playwright Test examples, check out our getting started docs.
This code snippet navigates to Playwright homepage and saves a screenshot.
import { test } from '@playwright/test';
test('Page Screenshot', async ({ page }) => {
await page.goto('https://playwright.dev/');
await page.screenshot({ path: `example.png` });
});
This snippet emulates Mobile Safari on a device at given geolocation, navigates to maps.google.com, performs the action and takes a screenshot.
import { test, devices } from '@playwright/test';
test.use({
...devices['iPhone 13 Pro'],
locale: 'en-US',
geolocation: { longitude: 12.492507, latitude: 41.889938 },
permissions: ['geolocation'],
})
test('Mobile and geolocation', async ({ page }) => {
await page.goto('https://maps.google.com');
await page.getByText('Your location').click();
await page.waitForRequest(/.*preview\/pwa/);
await page.screenshot({ path: 'colosseum-iphone.png' });
});
This code snippet navigates to example.com, and executes a script in the page context.
import { test } from '@playwright/test';
test('Evaluate in browser context', async ({ page }) => {
await page.goto('https://www.example.com/');
const dimensions = await page.evaluate(() => {
return {
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight,
deviceScaleFactor: window.devicePixelRatio
}
});
console.log(dimensions);
});
This code snippet sets up request routing for a page to log all network requests.
import { test } from '@playwright/test';
test('Intercept network requests', async ({ page }) => {
// Log and continue all network requests
await page.route('**', route => {
console.log(route.request().url());
route.continue();
});
await page.goto('http://todomvc.com');
});