现在位置: 首页 > Playwright 教程 > 正文

Playwright 测试

本章带领你编写并运行第一个 Playwright 测试,理解测试的基本组成和执行流程。


运行示例测试

初始化项目后,先运行一下自动生成的示例测试,确认一切正常:

# 运行所有测试
npx playwright test

运行后你会看到类似以下的输出:

Running 6 tests using 4 workers

  ✓  1 [chromium] › tests/example.spec.ts:3:1 › has title (2.1s)
  ✓  2 [chromium] › tests/example.spec.ts:10:1 › get started link (1.8s)
  ✓  3 [firefox] › tests/example.spec.ts:3:1 › has title (1.9s)
  ✓  4 [firefox] › tests/example.spec.ts:10:1 › get started link (1.7s)
  ✓  5 [webkit] › tests/example.spec.ts:3:1 › has title (2.3s)
  ✓  6 [webkit] › tests/example.spec.ts:10:1 › get started link (2.0s)

  6 passed (12s)

从输出中可以看到:测试在 3 个浏览器上各运行了 2 个测试,共 6 个测试全部通过。


创建第一个测试文件

清空 tests/example.spec.ts 的内容,我们来从头写一个测试。

实例

// 文件路径:tests/first-test.spec.ts
import { test, expect } from '@playwright/test';

// test(name, callback) 定义一个测试
// name:测试名称,会显示在测试报告中
// callback 的参数 { page } 是 Playwright 提供的 fixture(夹具)
test('访问 RUNOOB 首页并检查标题', async ({ page }) => {
  // 导航到指定 URL
  await page.goto('https://www.runoob.com/');

  // 断言:页面标题包含 "RUNOOB"
  await expect(page).toHaveTitle(/RUNOOB/);
});

运行这个测试:

npx playwright test tests/first-test.spec.ts

预期输出:

Running 1 test using 1 worker

  ✓  1 [chromium] › tests/first-test.spec.ts:4:1 › 访问 RUNOOB 首页并检查标题 (2.5s)

  1 passed (2.5s)

test() 函数详解

test() 是 Playwright Test 的核心函数,用于定义一个测试用例。

基本语法

实例

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

// test(测试名称, 测试函数)
test('测试的描述性名称', async ({ page }) => {
  // 测试中的操作
  await page.goto('https://example.com');

  // 测试中的断言
  await expect(page).toHaveTitle(/Example/);
});

参数说明

参数类型说明
第一个参数(测试名称)string测试的描述性名称,会显示在测试报告和日志中
第二个参数(测试函数)async (fixtures) => {}异步函数,包含测试的实际逻辑

page fixture 是什么

{ page } 是测试函数参数中的解构赋值,它从 Playwright 提供的 fixtures 对象中提取 page

page 是一个 Page 对象,代表了一个浏览器标签页。

每个测试都拥有自己独立的 page 实例:

fixture类型说明
pagePage 对象独立的浏览器标签页,用于导航、操作、断言
contextBrowserContext 对象浏览器上下文,管理 Cookie、Storage 等
browserBrowser 对象浏览器实例,较少直接使用
requestAPIRequestContext 对象用于发送 HTTP 请求(不通过浏览器)

最常用的是 page,绝大多数操作都通过它完成。


page.goto() 导航

page.goto(url) 是 Playwright 中最基础的操作之一,用来导航到指定 URL。

实例

// 基本用法
await page.goto('https://www.runoob.com/');

// 带选项的导航
await page.goto('https://www.runoob.com/', {
  // 等待直到 'load' 事件触发(默认值)
  waitUntil: 'load',
  // 操作超时时间(毫秒)
  timeout: 30000,
  // 引用来源(Referer 头)
  referer: 'https://www.google.com/',
});

waitUntil 选项有三个可选值:

含义适用场景
'load'等待 load 事件触发默认值,适用于大多数页面
'domcontentloaded'等待 DOMContentLoaded 事件页面基本结构加载完成即可
'networkidle'等待网络空闲(500ms 内无新请求)需要等待异步数据全部加载完毕

在绝大多数情况下使用默认的 'load' 即可,Playwright 的自动等待机制会处理后续的元素可用性问题,无需使用 'networkidle'


expect() 断言

expect() 是 Playwright 的断言方法,用来验证测试结果是否符合预期。

实例

// 页面标题断言
await expect(page).toHaveTitle(/RUNOOB/);

// 页面 URL 断言
await expect(page).toHaveURL('https://www.runoob.com/');

// 元素可见性断言
await expect(page.getByText('RUNOOB')).toBeVisible();

Playwright 的断言有一个关键特性:自动重试

如果断言条件暂时不满足,Playwright 会不断重试,直到条件满足或超时。

这意味着你不需要写 waitForsleep 来等待页面就绪。


测试的 async/await 模式

Playwright 的所有操作都是异步的,因此测试函数必须声明为 async

所有浏览器操作(gotoclickfill 等)和断言(expect)都必须使用 await 关键字。

实例

// 正确写法
test('正确示例', async ({ page }) => {
  await page.goto('https://www.runoob.com/');
  await expect(page).toHaveTitle(/RUNOOB/);
});

// 错误写法(缺少 await)
test('错误示例', async ({ page }) => {
  page.goto('https://www.runoob.com/');        // 没有 await!
  expect(page).toHaveTitle(/RUNOOB/);           // 没有 await!
});

如果忘记写 await,测试可能会在不正确的时机断言,导致测试不稳定或意外通过。务必在每次调用 Playwright API 时加上 await


理解测试输出

我们再看一个稍带断言失败的测试,以理解测试输出:

实例

// 文件路径:tests/fail-demo.spec.ts
import { test, expect } from '@playwright/test';

test('一个故意失败的测试', async ({ page }) => {
  await page.goto('https://www.runoob.com/');

  // 断言标题包含不存在的内容,预期会失败
  await expect(page).toHaveTitle(/不存在的文字/);
});

运行后,输出大致如下:

Running 1 test using 1 worker

  ✘  1 [chromium] › tests/fail-demo.spec.ts:4:1 › 一个故意失败的测试 (5.2s)

  1 failed
    tests/fail-demo.spec.ts:4:1 › 一个故意失败的测试

同时会自动打开 HTML 报告,显示详细的失败信息和错误截图。