Playwright E2E 测试 — 微软出品的跨浏览器自动化测试框架¶
一句话说明¶
Playwright 是微软开源的端到端(E2E)测试框架,用一套代码测试 Chrome、Firefox、Safari 三大浏览器,支持自动等待、网络拦截、截图比对,当前版本 v1.50+(2025年持续更新)。
安装与配置¶
# 初始化 Playwright 项目(推荐)
npm init playwright@latest
# 会交互式询问:语言、测试目录、是否装浏览器等
# 手动安装
npm install -D @playwright/test # 安装测试框架
npx playwright install # 下载 Chromium/Firefox/WebKit 浏览器二进制
# 只安装指定浏览器(节省空间)
npx playwright install chromium # 只装 Chrome
npx playwright install --with-deps # 同时安装系统依赖
# 查看版本
npx playwright --version
// playwright.config.ts — 配置文件
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests', // 测试文件目录
fullyParallel: true, // 所有测试并行执行
retries: process.env.CI ? 2 : 0, // CI 环境失败重试2次
workers: process.env.CI ? 1 : undefined, // CI 单进程,本地自动
reporter: 'html', // 生成 HTML 测试报告
use: {
baseURL: 'http://localhost:5173', // 测试的基础 URL
trace: 'on-first-retry', // 失败重试时记录 trace(调试神器)
screenshot: 'only-on-failure', // 失败时截图
video: 'retain-on-failure', // 失败时保留视频
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }, // Chrome 测试
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } }, // Firefox 测试
{ name: 'webkit', use: { ...devices['Desktop Safari'] } }, // Safari 测试
{ name: 'Mobile', use: { ...devices['iPhone 14'] } }, // 移动端测试
],
// 运行测试前启动开发服务器
webServer: {
command: 'npm run dev', // 启动命令
url: 'http://localhost:5173', // 等待这个 URL 可访问
reuseExistingServer: !process.env.CI, // 本地复用已有服务器
},
});
核心用法¶
// tests/example.spec.ts
import { test, expect } from '@playwright/test'; // 导入测试函数
test('用户登录流程', async ({ page }) => { // page 是浏览器页面对象
// ── 导航 ──
await page.goto('/login'); // 打开登录页
// ── 填写表单 ──
await page.fill('[name=username]', 'testuser'); // 填写用户名
await page.fill('[name=password]', 'password'); // 填写密码
await page.click('button[type=submit]'); // 点击提交按钮
// ── 断言(自动等待,无需 sleep)──
await expect(page).toHaveURL('/dashboard'); // 应该跳转到 dashboard
await expect(page.locator('h1')).toHaveText('欢迎回来'); // 标题应该显示欢迎
// ── 截图(可视化回归测试)──
await expect(page).toHaveScreenshot('dashboard.png'); // 与基准图比较
});
test('搜索功能', async ({ page }) => {
await page.goto('/');
// 使用角色选择器(更稳健,不依赖 CSS class)
const searchInput = page.getByRole('searchbox', { name: '搜索基因' });
await searchInput.fill('TP53'); // 输入搜索词
await searchInput.press('Enter'); // 按回车
// 等待结果出现
const results = page.locator('.search-result');
await expect(results).toHaveCount(5); // 应有5个结果
});
实战案例¶
// ── 测试生信工具的文件上传功能 ──
import { test, expect } from '@playwright/test';
import path from 'path';
test('上传 FASTQ 文件并运行质控', async ({ page }) => {
await page.goto('/tools/qc');
// ── 文件上传 ──
const fileInput = page.locator('input[type=file]');
await fileInput.setInputFiles(
path.join(__dirname, 'fixtures/sample.fastq') // 测试用的小 FASTQ 文件
);
// ── 等待上传完成 ──
await expect(page.locator('.upload-success')).toBeVisible(); // 成功提示可见
// ── 点击运行按钮 ──
await page.click('button:has-text("运行 QC")');
// ── 等待分析完成(可能需要较长时间)──
await expect(page.locator('.qc-report')).toBeVisible({ timeout: 60000 }); // 最多等60秒
// ── 验证报告内容 ──
const totalReads = page.locator('[data-testid=total-reads]');
await expect(totalReads).not.toHaveText('0'); // 总读段数不为0
// ── 下载报告 ──
const downloadPromise = page.waitForEvent('download'); // 等待下载事件
await page.click('button:has-text("下载报告")');
const download = await downloadPromise;
expect(download.suggestedFilename()).toContain('.html'); // 下载的应该是 HTML 文件
});
// ── API 拦截(Mock 后端)──
test('在无后端情况下测试前端', async ({ page }) => {
// 拦截 API 请求,返回 mock 数据
await page.route('/api/genes', async route => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify([
{ id: 1, name: 'TP53', expression: 3.2 }, // mock 基因数据
{ id: 2, name: 'BRCA1', expression: 1.5 },
]),
});
});
await page.goto('/genes');
await expect(page.locator('.gene-card')).toHaveCount(2); // 应渲染2张卡片
});
常见报错与解决¶
| 报错 | 原因 | 解决方法 |
|---|---|---|
Timeout 30000ms exceeded | 元素未出现或操作太慢 | 增加 timeout,或检查选择器是否正确 |
Error: browserType.launch | 浏览器二进制未安装 | 运行 npx playwright install |
| 截图比较失败 | 基准图过期 | 运行 npx playwright test --update-snapshots 更新基准 |
| CI 中测试不稳定 | 并发太多 | 设置 workers: 1 或增加 retries: 2 |
page.fill 找不到元素 | 选择器错误 | 用 npx playwright codegen 自动生成选择器 |
速查表¶
# 运行测试
npx playwright test # 运行所有测试
npx playwright test tests/login.spec.ts # 运行指定文件
npx playwright test --headed # 有界面模式(能看到浏览器操作)
npx playwright test --debug # 调试模式(可断点)
npx playwright test --ui # 启动 Playwright UI 界面
# 生成代码
npx playwright codegen http://localhost:5173 # 录制操作,自动生成测试代码
# 查看报告
npx playwright show-report # 打开上次测试的 HTML 报告
# 更新截图基准
npx playwright test --update-snapshots
# 常用选择器
page.getByRole('button', { name: '提交' }) # 按角色选择(推荐)
page.getByText('欢迎') # 按文本内容
page.getByTestId('submit-btn') # 按 data-testid
page.locator('#id .class') # CSS 选择器(备用)
# 官方文档:https://playwright.dev/docs/intro