playwright vs selenium-webdriver vs nightmare vs puppeteer
浏览器自动化与端到端测试工具选型指南
playwrightselenium-webdrivernightmarepuppeteer类似的npm包:

浏览器自动化与端到端测试工具选型指南

nightmareplaywrightpuppeteerselenium-webdriver 都是用于控制浏览器进行自动化测试、爬虫或生成截图的 Node.js 库。selenium-webdriver 是历史最悠久的标准方案,支持多语言和多浏览器;puppeteer 由 Google 维护,专注于 Chromium 生态;playwright 由 Microsoft 开发,支持多浏览器并提供了现代化的自动等待机制;而 nightmare 基于 Electron,目前已不再维护。这些工具虽然目标相似,但在架构设计、浏览器支持范围和长期维护性上存在显著差异。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
playwright37,148,79683,8373.72 MB6071 个月前Apache-2.0
selenium-webdriver1,984,76334,09517.9 MB20318 天前Apache-2.0
nightmare12,47619,966-2037 年前MIT
puppeteer093,77463 kB2905 天前Apache-2.0

浏览器自动化方案深度对比:Playwright、Puppeteer、Selenium 与 Nightmare

在 Node.js 生态中,控制浏览器进行自动化测试或数据抓取是一项常见需求。nightmareplaywrightpuppeteerselenium-webdriver 是四个最具代表性的解决方案。虽然它们都能完成“打开浏览器、点击按钮、获取内容”这类任务,但在底层实现、维护状态和开发体验上有着本质区别。作为架构师,我们需要从工程落地的角度深入分析它们的差异。

⚠️ 维护状态与生命周期

这是选型时最关键的决策点。一个不再维护的库会带来安全隐患和技术债务。

nightmare 已经停止维护。

  • 最后更新时间停留在数年前。
  • 基于旧版本 Electron,无法支持现代 Web 标准。
  • 建议:绝对不要在新项目中使用。
// nightmare: 已废弃,仅作历史参考
const Nightmare = require('nightmare');
const nightmare = Nightmare({ show: false });

nightmare
  .goto('https://example.com')
  .click('button')
  .end()
  .then(function(result) {
    console.log(result);
  });

playwright 处于活跃维护中。

  • 由 Microsoft 团队支持,更新频繁。
  • 定期添加对新浏览器版本的支持。
// playwright: 现代且活跃
const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await browser.close();
})();

puppeteer 处于活跃维护中。

  • 由 Google Chrome 团队支持。
  • 紧跟 Chromium 版本更新。
// puppeteer: 现代且活跃
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await browser.close();
})();

selenium-webdriver 处于活跃维护中。

  • 由开源社区和各大浏览器厂商共同支持。
  • 作为 W3C 标准实现,生命周期长。
// selenium-webdriver: 标准且稳定
const { Builder, By } = require('selenium-webdriver');

(async function example() {
  let driver = await new Builder().forBrowser('chrome').build();
  await driver.get('https://example.com');
  await driver.quit();
})();

🌐 浏览器支持范围

不同的业务场景需要不同的浏览器内核支持。

playwright 支持三大内核。

  • 原生支持 Chromium、Firefox 和 WebKit (Safari)。
  • 一套代码可同时在三个浏览器上运行测试。
// playwright: 多浏览器支持
const { chromium, firefox, webkit } = require('playwright');

async function testAll() {
  for (const browserType of [chromium, firefox, webkit]) {
    const browser = await browserType.launch();
    // 运行测试逻辑...
    await browser.close();
  }
}

puppeteer 主要支持 Chromium。

  • 专注于 Chrome/Chromium 生态。
  • 虽然可以通过配置连接 Firefox,但主要优势在 Chrome。
// puppeteer: 专注 Chromium
const puppeteer = require('puppeteer');

(async () => {
  // 默认启动 Chromium
  const browser = await puppeteer.launch({ product: 'chrome' });
  // Firefox 支持有限且配置复杂
})();

selenium-webdriver 支持所有主流浏览器。

  • 通过 WebDriver 协议连接 Chrome、Firefox、Safari、Edge 等。
  • 需要单独下载和管理对应的 Driver 二进制文件。
// selenium-webdriver: 广泛支持
const { Builder } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
const firefox = require('selenium-webdriver/firefox');

// 启动 Chrome
let driverChrome = await new Builder().forBrowser('chrome').build();
// 启动 Firefox
let driverFirefox = await new Builder().forBrowser('firefox').build();

nightmare 仅支持 Electron。

  • 本质是控制一个无头的 Electron 实例。
  • 无法测试真实 Safari 或 Firefox 环境。
// nightmare: 仅 Electron
const Nightmare = require('nightmare');
// 无法切换浏览器内核,仅限于 Electron 环境
const nightmare = Nightmare({ show: false });

⏳ 元素交互与自动等待

现代 Web 应用大量使用异步加载,如何处理元素等待是测试稳定性的核心。

playwright 内置智能自动等待。

  • 在执行操作前自动检查元素是否可见、可交互。
  • 减少了大量手动 waitFor 代码。
// playwright: 自动等待
const page = await browser.newPage();
await page.goto('https://example.com');
// 自动等待按钮可见且可点击
await page.click('#submit-button');

puppeteer 需要部分手动等待。

  • 提供了 waitForSelector,但点击操作本身不总是隐含等待。
  • 开发者需更小心处理竞态条件。
// puppeteer: 需显式等待
const page = await browser.newPage();
await page.goto('https://example.com');
// 通常需要先等待元素出现
await page.waitForSelector('#submit-button');
await page.click('#submit-button');

selenium-webdriver 需要显式等待配置。

  • 默认不等待元素,直接操作会报错。
  • 必须使用 WebDriverWait 来保证稳定性。
// selenium-webdriver: 显式等待
const { until } = require('selenium-webdriver');
await driver.get('https://example.com');
// 必须显式定义等待条件
let element = await driver.wait(until.elementLocated(By.id('submit-button')));
await element.click();

nightmare 链式调用隐含等待。

  • 通过队列机制按顺序执行,一定程度上简化了等待。
  • 但在复杂动态场景下不够灵活。
// nightmare: 链式隐含等待
nightmare
  .goto('https://example.com')
  .wait('#submit-button') // 需显式调用 wait
  .click('#submit-button');

📸 截图与 PDF 生成

这些功能常用于生成报告或爬虫存档。

playwright 支持全功能截图与 PDF。

  • 支持全屏、特定元素截图。
  • PDF 生成效果优秀。
// playwright: 截图与 PDF
await page.screenshot({ path: 'example.png', fullPage: true });
await page.pdf({ path: 'report.pdf', format: 'A4' });

puppeteer 截图与 PDF 是其强项。

  • API 设计非常直观。
  • 在生成服务端渲染预览方面表现极佳。
// puppeteer: 截图与 PDF
await page.screenshot({ path: 'example.png', fullPage: true });
await page.pdf({ path: 'report.pdf', format: 'A4' });

selenium-webdriver 仅支持截图。

  • 不支持原生 PDF 生成。
  • 截图通常需要转换 Base64 或保存文件。
// selenium-webdriver: 仅截图
let png = await driver.takeScreenshot();
// 需要手动处理 png 数据写入文件
// 不支持 page.pdf()

nightmare 支持截图。

  • 功能较为基础。
  • 不支持 PDF 生成。
// nightmare: 仅截图
await nightmare.screenshot('example.png');
// 不支持 PDF

📊 核心特性对比总结

特性playwrightpuppeteerselenium-webdrivernightmare
维护状态✅ 活跃 (Microsoft)✅ 活跃 (Google)✅ 活跃 (社区标准)❌ 已停止维护
浏览器内核Chromium, Firefox, WebKit主要 Chromium所有 (通过 Driver)Electron 仅
自动等待✅ 智能内置⚠️ 部分支持❌ 需手动配置⚠️ 链式隐含
API 风格现代 Promise/Async现代 Promise/Async经典 Promise/Async链式调用
PDF 支持✅ 支持✅ 支持❌ 不支持❌ 不支持
适用场景端到端测试、跨浏览器爬虫、PDF、Chrome 测试传统测试、多语言协作旧项目维护 (不推荐)

💡 架构师建议

playwright 是现代端到端测试的首选 🏆。

  • 它的多浏览器支持解决了 Safari 和 Firefox 的测试盲区。
  • 智能等待机制大幅降低了测试用例的 flakiness (不稳定性)。
  • 适合新启动的测试项目或需要高可靠性的 CI/CD 流程。

puppeteer 是 Chrome 生态工具的最佳搭档 🛠️。

  • 如果你只需要针对 Chrome 用户,或者需要生成 PDF 报告、进行无头爬虫,它比 Playwright 更轻量。
  • 在调试 Chrome 特定问题时,它与 DevTools 的集成度最高。

selenium-webdriver 是企业遗留系统的稳定基石 🏢。

  • 如果团队已有 Selenium Grid 投资,或需要测试 IE 等老旧浏览器(通过特定配置),它仍是标准。
  • 适合多语言混合开发的大型组织,因为它的 bindings 最齐全。

nightmare 应被逐步淘汰 🗑️。

  • 它的存在主要是历史遗留原因。
  • 继续使用该库会增加安全风险和维护成本,迁移成本远低于长期维护的代价。

🚀 总结

在选择浏览器自动化库时,维护状态浏览器覆盖范围是两个决定性因素。playwright 凭借其现代化的设计和跨浏览器能力,已成为大多数新项目的默认选择。puppeteer 在 Chrome 特定任务上依然保持优势。selenium-webdriver 则继续服务于需要广泛兼容性和标准协议的场景。而 nightmare 已完成了它的历史使命,不应再出现在新的技术栈中。

如何选择: playwright vs selenium-webdriver vs nightmare vs puppeteer

  • playwright:

    如果需要跨浏览器测试(包括 WebKit、Firefox 和 Chromium)或构建高可靠性的端到端测试,请选择 playwright。它提供了强大的自动等待功能、网络拦截能力和现代化的 API 设计,非常适合现代 Web 应用的复杂交互场景。

  • selenium-webdriver:

    当需要支持非 Chromium 内核的老旧浏览器,或者团队已经建立了基于 Selenium Grid 的基础设施时,选择 selenium-webdriver。它是行业标准,语言绑定丰富,但配置相对繁琐,运行速度通常慢于现代无头浏览器方案。

  • nightmare:

    不建议在新项目中选择 nightmare。该库已停止维护多年,基于旧版 Electron,存在安全漏洞且不支持现代浏览器特性。如果维护旧项目,建议尽快迁移到 playwrightpuppeteer 以获得更好的稳定性和支持。

  • puppeteer:

    如果项目主要依赖 Chrome 或 Chromium,或者需要生成 PDF、截取页面截图以及进行无头爬虫开发,puppeteer 是理想选择。它与 Chrome DevTools 协议深度集成,启动速度快,且在 Google 生态内更新及时。

playwright的README

🎭 Playwright

npm version Chromium version Firefox version WebKit version Join Discord

Documentation | API reference

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.

LinuxmacOSWindows
Chromium 145.0.7632.6:white_check_mark::white_check_mark::white_check_mark:
WebKit 26.0:white_check_mark::white_check_mark::white_check_mark:
Firefox 146.0.1: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?

Installation

Playwright has its own test runner for end-to-end tests, we call it Playwright Test.

Using init command

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.

Manually

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.

Capabilities

Resilient • No flaky tests

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.

No trade-offs • No limits

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.

Full isolation • Fast execution

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.

Powerful Tooling

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?

Examples

To learn how to run these Playwright Test examples, check out our getting started docs.

Page screenshot

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` });
});

Mobile and geolocation

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' });
});

Evaluate in browser context

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);
});

Intercept network requests

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');
});

Resources