Skip to content

Playwright Test ​

Playwright 除了作为浏览器自动化工具,还自带了一个 完整的测试框架 —— Playwright Test。

Playwright Test 可以帮助我们组织测试用例、生成报告、并行执行、失败重试,功能完备,开箱即用。

  1. Playwright Test 是一个 集成的测试框架,无需额外依赖。
  2. 配置文件可设置 超时、重试、报告、浏览器项目等。
  3. 测试用例支持 分组、钩子、数据驱动。
  4. 提供 并行执行、HTML 报告、失败重试 等高级能力。

测试框架概述 ​

  • 集成测试框架:自带测试运行器,无需额外安装 Jest、Mocha。
  • 内置断言库:支持 expect 断言。
  • 测试隔离:每个 test 默认在新的浏览器上下文中执行,互不干扰。
  • 丰富功能:并行执行、重试、截图、录制、HTML 报告等。

安装方式:

bash
npm init playwright@latest

自动生成项目结构,包含配置文件 playwright.config.js。

1. 配置文件详解 ​

Playwright Test 使用 playwright.config.js(或 .ts)作为配置入口。

bash
// 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、导入测试库

javascript
  import { test, expect } from '@playwright/test';

2、编写测试用例

javascript
test('示例测试', async ({ page }) => {
  await page.goto('https://example.com');
  await expect(page).toHaveTitle('Example Domain');
});

3、分组与钩子

  • 使用 describe 组织测试
  • 使用 beforeEach / afterEach 做前后置处理

编写测试用例 ​

1. test() 函数使用 ​

javascript
test('页面标题验证', async ({ page }) => {
  await page.goto('https://playwright.dev');
  await expect(page).toHaveTitle(/Playwright/);
});

2. describe() 分组 ​

javascript
test.describe('用户登录模块', () => {
  test('输入正确账号密码', async ({ page }) => {
    // 登录逻辑...
  });

  test('输入错误密码', async ({ page }) => {
    // 验证错误提示...
  });
});

3. 测试钩子 ​

javascript
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. 测试数据准备 ​

支持参数化测试:

javascript
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. 测试执行命令 ​

bash
npx playwright test          # 运行全部测试
npx playwright test login.spec.js   # 运行单个文件
npx playwright test -g "登录"       # 运行指定用例

2. 并行测试 ​

Playwright 默认 按文件并行执行,也可在配置文件中指定 workers 数量:

bash
npx playwright test --workers=4

3. 测试报告生成 ​

运行后生成 HTML 报告:

bash
npx playwright show-report

4. 失败重试机制 ​

在配置文件 playwright.config.js 中设置:

typescript
retries: 2

测试失败时会自动重试,适合处理偶发性错误。

  1. Playwright Test 是一个 集成的测试框架,无需额外依赖。
  2. 配置文件可设置 超时、重试、报告、浏览器项目等。
  3. 测试用例支持 分组、钩子、数据驱动。
  4. 提供 并行执行、HTML 报告、失败重试 等高级能力。

完整测试套件示例 ​

1、项目结构 ​

typescript
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) ​

实例 ​

bash
// 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 + 公共步骤封装)

实例 ​

bash
// fixtures/test.extend.ts

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(页面对象)

实例 ​

bash
// 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" 项目里执行)

实例 ​

javascript
// tests/auth.setup.ts

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

实例 ​

javascript
import { test, expect } from '@playwright/test';

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

实例 ​

javascript
import { test, expect } from '../../fixtures/test.extend';

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、运行与报告 ​

常用命令:

bash
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/AttributeWeb 特有断言(带智能等待)
expect(locator).toBeVisible/Hidden/Enabled/Disabled/Checked状态断言
expect(page).toHaveTitle/URL页面断言
`expect(page/locator).toHaveScreenshot([nameoptions])`视觉快照对比(推荐)

断言与视觉快照的推荐做法详见 Assertions 与 Snapshots 文档。(Playwright)

4、步骤与附件 ​

API作用
test.step(name, fn)将测试分解为步骤(报告可视化)
`test.info().attach(name, { pathbody, 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)

AI 思考中...

Playwright 数据提取和验证

Playwright 网络拦截

基于 VitePress 构建,部署于 GitHub Pages