Playwright Test
Playwright 除了作为浏览器自动化工具,还自带了一个 完整的测试框架 —— Playwright Test。
Playwright Test 可以帮助我们组织测试用例、生成报告、并行执行、失败重试,功能完备,开箱即用。
- Playwright Test 是一个 集成的测试框架,无需额外依赖。
- 配置文件可设置 超时、重试、报告、浏览器项目等。
- 测试用例支持 分组、钩子、数据驱动。
- 提供 并行执行、HTML 报告、失败重试 等高级能力。
测试框架概述
- 集成测试框架:自带测试运行器,无需额外安装 Jest、Mocha。
- 内置断言库:支持
expect
断言。 - 测试隔离:每个
test
默认在新的浏览器上下文中执行,互不干扰。 - 丰富功能:并行执行、重试、截图、录制、HTML 报告等。
安装方式:
npm init playwright@latest
自动生成项目结构,包含配置文件 playwright.config.js
。
1. 配置文件详解
Playwright Test 使用 playwright.config.js
(或 .ts
)作为配置入口。
// playwright.config.js import { defineConfig } from '@playwright/test'; export default defineConfig({ testDir: './tests', // 测试目录 timeout: 30 * 1000, // 单个测试超时时间 retries: 2, // 失败重试次数 reporter: [['html'], ['list']], // 测试报告类型 use: { headless: true, // 是否无头模式 screenshot: 'only-on-failure', // 失败时截图 video: 'retain-on-failure', // 失败时保留视频 baseURL: 'https://example.com', // 基础 URL }, projects: [ { name: 'Chromium', use: { browserName: 'chromium' } }, { name: 'Firefox', use: { browserName: 'firefox' } }, { name: 'WebKit', use: { browserName: 'webkit' } }, ], });
2. 测试脚本结构
Playwright Test 脚本通常包含:
1、导入测试库
import { test, expect } from '@playwright/test';
2、编写测试用例
test('示例测试', async ({ page }) => { await page.goto('https://example.com'); await expect(page).toHaveTitle('Example Domain'); });
3、分组与钩子
- 使用
describe
组织测试 - 使用
beforeEach
/afterEach
做前后置处理
编写测试用例
1. test()
函数使用
test('页面标题验证', async ({ page }) => { await page.goto('https://playwright.dev'); await expect(page).toHaveTitle(/Playwright/); });
2. describe()
分组
test.describe('用户登录模块', () => { test('输入正确账号密码', async ({ page }) => { // 登录逻辑... }); test('输入错误密码', async ({ page }) => { // 验证错误提示... }); });
3. 测试钩子
test.describe('购物车模块', () => { test.beforeEach(async ({ page }) => { await page.goto('https://example.com/cart'); }); test.afterEach(async ({ page }) => { await page.screenshot({ path: 'cart.png' }); }); test('添加商品', async ({ page }) => { await page.click('#add-item'); await expect(page.locator('#cart-count')).toHaveText('1'); }); });
4. 测试数据准备
支持参数化测试:
const users = [ { name: 'admin', password: '123456' }, { name: 'guest', password: 'guest' }, ]; for (const user of users) { test(`用户 ${user.name} 登录`, async ({ page }) => { await page.goto('https://example.com/login'); await page.fill('#username', user.name); await page.fill('#password', user.password); await page.click('#submit'); await expect(page.locator('.welcome')).toBeVisible(); }); }
运行和报告
1. 测试执行命令
npx playwright test # 运行全部测试 npx playwright test login.spec.js # 运行单个文件 npx playwright test -g "登录" # 运行指定用例
2. 并行测试
Playwright 默认 按文件并行执行,也可在配置文件中指定 workers 数量:
npx playwright test --workers=4
3. 测试报告生成
运行后生成 HTML 报告:
npx playwright show-report
4. 失败重试机制
在配置文件 playwright.config.js
中设置:
retries: 2
测试失败时会自动重试,适合处理偶发性错误。
- Playwright Test 是一个 集成的测试框架,无需额外依赖。
- 配置文件可设置 超时、重试、报告、浏览器项目等。
- 测试用例支持 分组、钩子、数据驱动。
- 提供 并行执行、HTML 报告、失败重试 等高级能力。
完整测试套件示例
1、项目结构
playwright-demo/ ├─ playwright.config.ts # 全局配置(多项目、多浏览器、报告、重试…) ├─ package.json ├─ tests/ │ ├─ auth.setup.ts # 一次性登录,生成 storageState │ ├─ smoke/ │ │ └─ home.spec.ts # 冒烟用例:标题/URL/截图对比 │ └─ e2e/ │ └─ cart.spec.ts # 端到端:添加购物车、断言、附件、步骤 ├─ fixtures/ │ ├─ pages.ts # 页面对象(PO) │ └─ test.extend.ts # 自定义 fixtures └─ snapshots/ # 视觉基线(自动生成)
2、配置文件(playwright.config.ts)
实例
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
timeout: 30_000,
retries: 2,
workers: 4,
reporter: [['html', { outputFolder: 'report' }], ['list']],
forbidOnly: !!process.env.CI,
// 统一默认使用(可在项目或测试级覆盖)
use: {
baseURL: 'https://demo.playwright.dev',
headless: true,
screenshot: 'only-on-failure',
video: 'retain-on-failure',
trace: 'retain-on-failure',
viewport: { width: 1366, height: 900 },
locale: 'zh-CN',
},
// 多项目:不同浏览器/设备/登录态
projects: [
{ name: 'Chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'Firefox', use: { ...devices['Desktop Firefox'] } },
{
name: 'Mobile Chrome',
use: { ...devices['Pixel 7'], headless: true },
},
// 带登录态项目(复用 storageState)
{
name: 'Chromium Logged-in',
use: { storageState: 'storageState.json' },
dependencies: ['setup'], // 依赖前置项目生成登录态
},
// 前置"setup"项目:只跑一次生成 storageState
{
name: 'setup',
testMatch: /auth\.setup\.ts/,
},
],
});
要点:projects 让同一套用例在不同浏览器/配置下运行;use 可在全局/项目/测试三级覆盖;报告与重试在配置中统一管理。
3、夹具与页面对象
fixtures/test.extend.ts(自定义 fixture + 公共步骤封装)
实例
import { test as base } from '@playwright/test';
import { HomePage, CartPage } from './pages';
type MyFixtures = {
home: HomePage;
cart: CartPage;
};
export const test = base.extend<MyFixtures>({
home: async ({ page }, use) => {
const home = new HomePage(page);
await use(home);
},
cart: async ({ page }, use) => {
const cart = new CartPage(page);
await use(cart);
},
});
export { expect } from '@playwright/test';
基于 test.extend() 增加自定义 fixture,便于在任意用例中直接注入 home、cart 实例。
fixtures/pages.ts(页面对象)
实例
import { Page, expect } from '@playwright/test';
export class HomePage {
constructor(private page: Page) {}
async goto() { await this.page.goto('/'); }
get tryTodoLink() { return this.page.getByRole('link', { name: /ToDo MVC/i }); }
}
export class CartPage {
constructor(private page: Page) {}
async goto() { await this.page.goto('/e2e'); } // 假设存在 e2e 示例页
get addFirstItem() { return this.page.getByRole('button', { name: /Add .* #1/i }); }
get cartCount() { return this.page.locator('[data-test=cart-count]'); }
async addOne() { await this.addFirstItem.click(); }
async expectCount(n: number) { await expect(this.cartCount).toHaveText(String(n)); }
}
4、前置登录(一次性生成 storageState)
tests/auth.setup.ts(仅在 "setup" 项目里执行)
实例
import { test, expect } from '@playwright/test';
test('create storageState', async ({ page }) => {
await page.goto('https://demo.playwright.dev/todomvc');
// ……此处替换为你的登录流程……
// 假设已登录成功
await expect(page).toHaveURL(/todomvc/);
await page.context().storageState({ path: 'storageState.json' });
});
5、冒烟测试(标题/URL/视觉对比)
tests/smoke/home.spec.ts
实例
test.describe('Smoke - Home', () => {
test('title & url & visual snapshot', async ({ page }) => {
await page.goto('https://playwright.dev');
await expect(page).toHaveTitle(/Playwright/);
await expect(page).toHaveURL(/playwright\.dev/);
// 视觉回归(自动生成/比对基线)
await expect(page).toHaveScreenshot(); // 首次运行会生成基线
});
});
视觉对比建议使用 toHaveScreenshot(优先于用 page.screenshot() + toMatchSnapshot 的手写方式)。
6、端到端测试(步骤、附件、断言)
tests/e2e/cart.spec.ts
实例
test.describe.configure({ mode: 'parallel' });
test.describe('E2E - Cart', () => {
test.beforeEach(async ({ home }) => {
await test.step('进入首页', async () => {
await home.goto();
});
});
test('添加商品到购物车(含附件与断言)', async ({ page, cart }) => {
await test.step('进入购物页并添加商品', async () => {
await cart.goto();
await cart.addOne();
await cart.expectCount(1);
});
await test.step('附加调试信息到报告', async () => {
await test.info().attach('state.json', {
contentType: 'application/json',
body: Buffer.from(JSON.stringify({ ts: Date.now(), note: 'after add' })),
});
});
// 元素级截图
await test.step('元素截图', async () => {
const badge = page.locator('[data-test=cart-count]');
await expect(badge).toBeVisible();
await expect(badge).toHaveScreenshot(); // 元素快照
});
});
});
用 test.step 分层记录步骤、用 test.info().attach()把调试数据/截图附加到报告,便于排查;并行模式可用 describe.configure({ mode: 'parallel' })。
7、运行与报告
常用命令:
npx playwright test # 运行全部 npx playwright test tests/e2e # 运行目录 npx playwright test -g "Cart" # 按标题过滤 npx playwright test --project="Chromium" # 指定项目 npx playwright show-report # 打开HTML报告 npx playwright test --update-snapshots # 更新视觉基线 npx playwright test --debug # 调试模式(Inspector)
CLI 过滤、项目选择、报告查看与快照更新等见官方 CLI/报告/快照文档。
常用相关 API 速查表(Playwright Test)
1、测试与分组
API | 作用 |
---|---|
test(name, fn) |
定义测试 |
test.describe(title, fn) |
分组 |
test.describe.configure({ mode }) |
parallel / serial |
test.beforeAll/afterAll |
组级前后置 |
test.beforeEach/afterEach |
用例前后置 |
test.skip/only/fixme/slow/fail |
标记/控制用例 |
2、夹具与配置
API | 作用 |
---|---|
test.extend<Fixtures>(defs) |
扩展自定义 fixtures |
test.use(options) |
测试级覆盖 use 选项(如 storageState 、viewport 、locale 等) |
defineConfig({...}) |
配置文件入口(testDir 、retries 、workers 、reporter …) |
projects |
多项目/多浏览器/不同配置运行 |
use: { baseURL, trace, video, screenshot, viewport, locale, timezoneId, storageState } |
运行时环境与采集策略 |
fixtures / use / 配置项与 projects 详见官方 "Fixtures / Use options / Configuration / Projects" 文档。(Playwright)
3、断言(expect)
API | 作用 | |
---|---|---|
expect(value).toBe / toEqual / toContain ... |
通用断言 | |
expect(locator).toHaveText/Value/Attribute |
Web 特有断言(带智能等待) | |
expect(locator).toBeVisible/Hidden/Enabled/Disabled/Checked |
状态断言 | |
expect(page).toHaveTitle/URL |
页面断言 | |
`expect(page/locator).toHaveScreenshot([name | options])` | 视觉快照对比(推荐) |
断言与视觉快照的推荐做法详见 Assertions 与 Snapshots 文档。(Playwright)
4、步骤与附件
API | 作用 | |
---|---|---|
test.step(name, fn) |
将测试分解为步骤(报告可视化) | |
`test.info().attach(name, { path | body, contentType })` | 给测试或步骤附加文件/数据(报告中展示) |
附件也可作用于步骤级(参见 TestStep / TestStepInfo)。(Playwright)
5、报告与 CLI
命令/配置 | 作用 |
---|---|
reporter: [['html', { outputFolder }], ['list']] |
报告配置 |
npx playwright test --project="Chromium" |
选择项目运行 |
-g "keyword" / --grep / --grep-invert |
过滤用例 |
--update-snapshots |
更新视觉基线 |
npx playwright show-report |
打开报告 |
完整 CLI 与 Reporter 选项见官方文档。(Playwright)
点我分享笔记