Playwright:微软开源的现代化浏览器自动化测试框架

Playwright:微软开源的现代化浏览器自动化测试框架

背景

提到浏览器自动化测试,Selenium 无疑是行业元老。但 Selenium 存在一些历史遗留问题:

  • 速度慢:启动浏览器、执行操作耗时较长
  • 不稳定:经常需要添加人工等待(sleep)
  • API 过时:设计年代久远,不够现代化
  • 维护困难:驱动兼容性问题层出不穷

作为现代替代方案,Playwright 由 Microsoft 开发,专为解决这些问题而生,在 GitHub 上持续获得大量关注。

什么是 Playwright?

Playwright 是一个用于 Web 测试和自动化的框架,支持使用单一 API 测试 Chromium、Firefox 和 WebKit 三大浏览器引擎。

核心特性:

特性 说明
微软出品 Microsoft 官方维护,质量有保障
三大浏览器 Chromium、Firefox、WebKit 原生支持
跨平台 Linux、macOS、Windows 全支持
多语言 Python、JavaScript、.NET、Java
自动等待 元素可操作才执行,告别人工 sleep
录制生成 可视化录制操作,自动生成测试代码
强大调试 内置 Inspector、Trace Viewer
移动端 支持模拟 iOS/Android 设备

GitHub 地址: https://github.com/microsoft/playwright

官网: https://playwright.dev

Playwright vs Selenium

对比项 Playwright Selenium
开发方 Microsoft 开源社区
浏览器支持 Chromium、Firefox、WebKit 多浏览器(需驱动)
速度 较慢
稳定性 高(自动等待) 需手动处理等待
API 设计 现代化 较旧
移动测试 原生支持 需 Appium
调试工具 强大内置工具 较弱
社区 快速增长 成熟庞大

Playwright 的核心优势:

  • 自动等待:元素出现后才操作,减少不稳定的 flaky tests
  • 速度快:浏览器上下文隔离,无缝并发执行
  • 功能全:截图、PDF、网络拦截、文件上传下载等
  • 易调试:内置录制、Inspector、Trace Viewer

快速上手

安装

Node.js 环境:

bash 复制代码
# 创建项目
npm init playwright@latest my-project
cd my-project

# 或手动安装
npm i -D @playwright/test
npx playwright install

Python 环境:

bash 复制代码
pip install playwright
python -m playwright install

Java 环境:

xml 复制代码
<dependency>
  <groupId>com.microsoft.playwright</groupId>
  <artifactId>playwright</artifactId>
  <version>1.44.0</version>
</dependency>

第一个测试

JavaScript 版本:

javascript 复制代码
const { test, expect } = require('@playwright/test');

test('我的第一个测试', async ({ page }) => {
  // 访问网页
  await page.goto('https://www.example.com');

  // 获取标题
  const title = await page.title();
  expect(title).toBe('Example Domain');

  // 截图
  await page.screenshot({ path: 'example.png' });
});

Python 版本:

python 复制代码
import pytest
from playwright.sync_api import sync_playwright

def test_my_first_test(page):
    page.goto('https://www.example.com')
    assert page.title() == 'Example Domain'
    page.screenshot(path='example.png')

运行测试

bash 复制代码
# 运行所有测试
npx playwright test

# 运行单个文件
npx playwright test tests/example.spec.ts

# 打开 UI 模式
npx playwright test --ui

# 生成测试报告
npx playwright show-report

核心功能详解

1. 强大的选择器

Playwright 支持多种选择器方式:

javascript 复制代码
// CSS 选择器
await page.click('button.submit');

// 文本选择器
await page.getByText('提交').click();

// 按标签和占位符
await page.getByPlaceholder('输入用户名').fill('admin');

// 按角色(无障碍友好)
await page.getByRole('button', { name: '提交' });

// 链式选择
await page.locator('form').getByRole('button').click();

2. 自动等待机制

Playwright 自动等待元素可操作:

javascript 复制代码
// 自动等待元素出现、可见、启用
await page.click('button.submit');

// 等待网络请求
await page.waitForResponse('**/api/data');

// 等待函数返回 true
await page.waitForFunction(() => window.status === 'ready');

// 等待导航完成
await page.goto('https://example.com', { waitUntil: 'networkidle' });

3. 浏览器上下文

隔离的浏览器上下文,加快测试速度:

javascript 复制代码
// 创建新上下文(相当于新浏览器配置)
const context = await browser.newContext();

// 上下文1:普通用户
const page1 = await context.newPage();
await page1.goto('https://example.com');

// 上下文2:已登录用户(复用登录状态)
const context2 = await browser.newContext();
const storage = await context2.storageState();
await context2.addCookies(storage.cookies);
const page2 = await context2.newPage();

4. 移动端测试

Playwright 内置移动设备模拟:

javascript 复制代码
const { test, devices } = require('@playwright/test');

test.use({
  ...devices['iPhone 13 Pro'],
  locale: 'zh-CN',
  geolocation: { longitude: 116.4, latitude: 39.9 },
  permissions: ['geolocation'],
});

test('移动端测试', async ({ page }) => {
  await page.goto('https://maps.google.com');
  // 测试移动端功能...
});

5. 网络拦截

拦截和修改网络请求:

javascript 复制代码
test('网络拦截示例', async ({ page }) => {
  // 监听请求
  await page.route('**/api/**', route => {
    // 修改请求
    route.continue({ headers: { ...route.request().headers(), 'X-Custom': 'value' } });
  });

  // 模拟响应
  await page.route('**/api/user', route => {
    route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify({ name: 'Test User', age: 25 }),
    });
  });

  await page.goto('https://example.com');
});

6. 文件操作

处理文件上传和下载:

javascript 复制代码
// 文件上传
await page.setInputFiles('input[type="file"]', 'path/to/file.pdf');

// 多文件上传
await page.setInputFiles('input[type="file"]', ['file1.pdf', 'file2.pdf']);

// 文件下载
const [download] = await Promise.all([
  page.waitForEvent('download'),
  page.click('button.download')
]);
await download.saveAs('path/to/save/file.pdf');

录制生成测试

Playwright 提供可视化的 Codegen 工具:

录制操作

bash 复制代码
# 启动录制工具
npx playwright codegen

# 指定浏览器和 URL
npx playwright codegen --browser=chromium https://www.example.com

录制为不同语言

bash 复制代码
# 录制为 Python
npx playwright codegen --target=python -o test.py

# 录制为 JavaScript
npx playwright codegen --target=javascript -o test.js

# 录制为 Java
npx playwright codegen --target=java -o Test.java

录制生成的代码示例:

javascript 复制代码
// Python 录制结果
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto("https://www.example.com")
    page.get_by_placeholder("Search").click()
    page.get_by_placeholder("Search").fill("playwright")
    page.get_by_role("button", name="Search").click()
    browser.close()

调试工具

Playwright Inspector

bash 复制代码
# 启动 Inspector
npx playwright open --inspector https://example.com

# 带调试模式运行
npx playwright test --debug

Inspector 功能:

  • 可视化页面检查
  • 生成选择器
  • 单步执行测试
  • 查看点击点

Trace Viewer

javascript 复制代码
// 在测试中添加 tracing
import { test } from '@playwright/test';

test('带追踪的测试', async ({ page }) => {
  await page.context().tracing.start({
    screenshots: true,
    snapshots: true,
  });

  await page.goto('https://example.com');
  // 执行测试操作...

  await page.context().tracing.stop({
    path: './trace.zip'
  });
});
bash 复制代码
# 查看追踪文件
npx playwright show-trace trace.zip

Trace Viewer 功能:

  • 视频回放
  • DOM 快照
  • 操作时间线
  • 网络请求详情

实战案例

案例1:电商网站下单流程

javascript 复制代码
test('完整下单流程', async ({ page }) => {
  // 1. 登录
  await page.goto('https://shop.example.com/login');
  await page.getByPlaceholder('邮箱').fill('user@example.com');
  await page.getByPlaceholder('密码').fill('password123');
  await page.getByRole('button', { name: '登录' }).click();

  // 2. 浏览商品
  await page.goto('https://shop.example.com/products');
  await page.locator('.product-card').first().click();

  // 3. 加入购物车
  await page.getByRole('button', { name: '加入购物车' }).click();
  await page.waitForSelector('.cart-badge');

  // 4. 结算
  await page.click('.cart-icon');
  await page.getByRole('button', { name: '去结算' }).click();

  // 5. 确认订单
  await page.getByRole('button', { name: '确认订单' }).click();

  // 6. 验证成功
  await expect(page.locator('.order-success')).toBeVisible();
});

案例2:API 响应测试

javascript 复制代码
test('API 响应测试', async ({ page }) => {
  const apiPromise = page.waitForResponse('**/api/user/profile');

  await page.goto('https://app.example.com/profile');

  const response = await apiPromise;
  const data = await response.json();

  expect(response.status()).toBe(200);
  expect(data).toHaveProperty('id');
  expect(data).toHaveProperty('name');
  expect(data.email).toMatch(/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/);
});

案例3:表单验证测试

javascript 复制代码
test('表单验证', async ({ page }) => {
  await page.goto('https://form.example.com/register');

  // 提交空表单
  await page.getByRole('button', { name: '注册' }).click();

  // 验证错误提示
  await expect(page.locator('.error-email')).toHaveText('请输入邮箱');
  await expect(page.locator('.error-password')).toHaveText('密码至少8位');

  // 输入无效邮箱
  await page.getByPlaceholder('邮箱').fill('invalid-email');
  await page.getByRole('button', { name: '注册' }).click();
  await expect(page.locator('.error-email')).toHaveText('邮箱格式不正确');
});

CI/CD 集成

GitHub Actions

yaml 复制代码
name: Playwright Tests
on: [push, pull_request]

jobs:
  test:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - name: Install dependencies
        run: npm ci
      - name: Install Playwright Browsers
        run: npx playwright install --with-deps
      - name: Run tests
        run: npx playwright test
      - name: Upload test results
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 30

Docker 运行

dockerfile 复制代码
FROM mcr.microsoft.com/playwright:v1.44.0-focal

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .

CMD ["npx", "playwright", "test"]

常见问题

Q:Playwright 和 Selenium 哪个更好?

A:根据场景选择:

  • 新项目、追求速度稳定性 → Playwright
  • 老项目、已有 Selenium 积累 → 继续用 Selenium
  • 需要 Java 语言支持且无 Python 经验 → Selenium

Q:支持哪些编程语言?

A:Python、JavaScript/TypeScript、.NET C#、Java 共 4 种官方 SDK。

Q:可以用于爬虫吗?

A:技术上可以,但建议:

  • 仅爬取公开数据
  • 遵守网站的 robots.txt
  • 不要对网站造成负担
  • 考虑道德和法律风险

Q:测试不稳定怎么办(flaky tests)?

A:

  • 使用 Playwright 的自动等待而非手动 sleep
  • 使用 page.waitForSelector() 显式等待
  • 配置合理的 timeout
  • 使用 Trace Viewer 调试

Q:如何提高测试速度?

A:

  • 使用 browser.newContext() 共享状态
  • 并行运行独立测试
  • 使用 headless: true 模式
  • 合理使用 page.context().tracing 避免全量追踪

总结

Playwright 用"自动等待 + 快速稳定 + 现代化 API"的组合,重新定义了浏览器自动化测试。

核心优势回顾:

  • 微软品质:Microsoft 官方维护,质量有保障
  • 三大浏览器:Chromium、Firefox、WebKit 原生支持
  • 自动等待:告别 flaky tests,稳定可靠
  • 速度飞快:浏览器上下文隔离,高效并发
  • 多语言支持:Python、JavaScript、.NET、Java
  • 强大调试:Codegen、Inspector、Trace Viewer

对于追求测试稳定性、开发效率的团队,Playwright 是浏览器自动化的最佳选择。


本文由无边界科技技术团队分享,专注软件开发与技术解决方案。

官网:wubianj.com

© 版权归无边界科技所有,版权所有。

相关推荐
白鲸开源2 小时前
SeaTunnel × Gravitino:Schema URL 驱动的表结构自动感知方案
大数据·人工智能·开源
dehuisun3 小时前
移动端智能体开源项目清单
开源
wdfk_prog3 小时前
MAX14830 可移植 C 驱动实现分析:一个适合多串口扩展场景的开源基础版本
c语言·开发语言·开源
计算机魔术师3 小时前
一键沉浸式体验:清华开源OpenMAIC,重塑多智能体学习新范式
学习·typescript·开源·多智能体·openmaic
悟空码字3 小时前
免费使用了!开源一款自习室预约系统,支持门店浏览、座位选择、时间预约等核心功能
开源·预约系统·自习室预约系统
MuShan-bit3 小时前
CSDN-推荐开源项目-auto-x-to-wechat
爬虫·微信·开源·node.js·twitter
亥时科技3 小时前
开源赋能低空经济:AI 无人机一体化平台如何破解行业应用难题
人工智能·开源·无人机