最佳实践
简介
本指南将帮助您遵循我们的最佳实践,编写更具健壮性的测试用例。
测试理念
测试用户可见行为
自动化测试应当验证应用程序代码对终端用户是否正常工作,避免依赖实现细节——即那些用户通常不会使用、看到甚至不知道的内部信息,例如函数名称、某个变量是否为数组、元素的CSS类名等。终端用户只会与页面渲染的内容交互,因此您的测试通常也应当只关注/交互这些相同的渲染输出。
尽可能保持测试隔离性
每个测试都应与其他测试完全隔离,并能够独立运行,拥有自己的本地存储、会话存储、数据和 cookies 等。测试隔离可以提高测试的可重复性,使调试更简单,并防止级联测试失败。
为了避免测试中特定部分的重复代码,你可以使用前置和后置钩子。在测试文件中添加前置钩子,在每个测试前运行部分代码,例如访问特定 URL 或登录应用。这样可以保持测试隔离性,因为没有任何测试依赖于其他测试。不过,当测试足够简单时,少量重复代码也是可以接受的,特别是如果这样能让测试更清晰、更易读和维护。
import { test } from '@playwright/test';
test.beforeEach(async ({ page }) => {
// 在每个测试前运行,为每个页面执行登录操作
await page.goto('https://github.com/login');
await page.getByLabel('Username or email address').fill('username');
await page.getByLabel('Password').fill('password');
await page.getByRole('button', { name: 'Sign in' }).click();
});
test('first', async ({ page }) => {
// 页面已登录
});
test('second', async ({ page }) => {
// 页面已登录
});
你也可以通过设置项目在测试间复用登录状态。这样你只需登录一次,就可以在所有测试中跳过登录步骤。
避免测试第三方依赖
只测试你能控制的内容。不要尝试测试你无法控制的外部站点或第三方服务器的链接。这不仅耗时且会拖慢测试速度,而且你无法控制所链接页面的内容,或者是否存在 Cookie 横幅、覆盖页面等可能导致测试失败的元素。
相反,应该使用 Playwright 网络 API 来确保获得所需的响应。
await page.route('**/api/fetch_data_third_party_dependency', route => route.fulfill({
status: 200,
body: testData,
}));
await page.goto('https://example.com');
数据库测试
如果涉及数据库操作,请确保你能控制数据。在预发布环境中进行测试,并确保数据不会变化。对于视觉回归测试,请确保操作系统和浏览器版本保持一致。
最佳实践
使用定位器
为了编写端到端测试,我们首先需要在网页上定位元素。这可以通过 Playwright 内置的 定位器 来实现。定位器具有自动等待和重试机制。自动等待意味着 Playwright 会对元素执行一系列可操作性检查,例如确保元素在执行点击操作前是可见且启用的。为了使测试更加健壮,我们建议优先使用面向用户的属性和显式约定。
// 👍
page.getByRole('button', { name: 'submit' });
使用链式调用和过滤
定位器可以通过链式调用来缩小搜索范围到页面的特定部分。
const product = page.getByRole('listitem').filter({ hasText: 'Product 2' });
你也可以通过文本或其他定位器来过滤定位器。
await page
.getByRole('listitem')
.filter({ hasText: 'Product 2' })
.getByRole('button', { name: 'Add to cart' })
.click();
优先使用面向用户的属性而非 XPath 或 CSS 选择器
DOM 结构很容易发生变化,如果测试依赖于 DOM 结构可能会导致测试失败。例如考虑通过 CSS 类来选择这个按钮。如果设计师做了修改,类名可能会改变,从而导致测试中断。
// 👎
page.locator('button.buttonIcon.episode-actions-later');
使用对 DOM 变化具有弹性的定位器。
// 👍
page.getByRole('button', { name: 'submit' });
生成定位器
Playwright 提供了测试生成器,可以为你生成测试并选择定位器。它会分析你的页面并找出最佳的定位器,优先考虑角色、文本和测试 ID 定位器。如果生成器发现多个元素匹配定位器,它会优化定位器使其具有弹性并唯一标识目标元素,因此你无需担心因定位器问题导致测试失败。
使用 codegen
生成定位器
要选择定位器,请运行 codegen
命令,后跟您想要从中选择定位器的 URL。
- npm
- yarn
- pnpm
npx playwright codegen playwright.dev
yarn playwright codegen playwright.dev
pnpm exec playwright codegen playwright.dev
这将打开一个新的浏览器窗口以及 Playwright 检查器。要选择定位器,首先点击"Record"按钮停止录制。默认情况下,当您运行 codegen
命令时,它会开始新的录制。停止录制后,"Pick Locator"按钮将变为可点击状态。
然后您可以在浏览器窗口中悬停页面上的任何元素,光标下方会高亮显示定位器。点击元素会将定位器添加到 Playwright 检查器中。您可以直接复制定位器粘贴到测试文件中,或者继续在 Playwright 检查器中编辑定位器(例如修改文本)并在浏览器窗口中查看结果。

使用 VS Code 扩展生成定位器
您也可以使用 VS Code 扩展来生成定位器以及录制测试。VS Code 扩展在编写、运行和调试测试时提供了出色的开发体验。

使用 Web 优先断言
断言是验证预期结果与实际结果是否匹配的一种方式。通过使用 Web 优先断言,Playwright 会等待直到满足预期条件。例如,在测试警报消息时,测试会点击一个使消息出现的按钮,并检查警报消息是否存在。如果警报消息需要半秒钟才能出现,像 toBeVisible()
这样的断言会等待并在需要时重试。
// 👍
await expect(page.getByText('welcome')).toBeVisible();
// 👎
expect(await page.getByText('welcome').isVisible()).toBe(true);
不要使用手动断言
不要使用不等待 expect 的手动断言。在下面的代码中,await 位于 expect 内部而不是之前。当使用 isVisible()
这样的断言时,测试不会等待哪怕一秒钟,它只会检查定位器是否存在并立即返回。
// 👎
expect(await page.getByText('welcome').isVisible()).toBe(true);
应改用 toBeVisible()
这样的 Web 优先断言。
// 👍
await expect(page.getByText('welcome')).toBeVisible();
配置调试
本地调试
对于本地调试,我们推荐您通过安装 VS Code 扩展来在 VSCode 中实时调试测试。您可以通过右键点击测试行旁边的空白处来以调试模式运行测试,这将打开浏览器窗口并在设置的断点处暂停。

您可以在 VS Code 中点击或编辑测试中的定位器来进行实时调试,这会在浏览器窗口中高亮显示该定位器,并展示页面上所有其他匹配的定位器。

您也可以通过使用 --debug
标志运行测试,通过 Playwright 检查器来调试测试。
- npm
- yarn
- pnpm
npx playwright test --debug
yarn playwright test --debug
pnpm exec playwright test --debug
然后您可以逐步执行测试,查看可操作性日志,实时编辑定位器并在浏览器窗口中看到高亮显示。这将展示哪些定位器匹配以及匹配的数量。

要调试特定测试,请在 --debug
标志后添加测试文件名和测试行号。
- npm
- yarn
- pnpm
npx playwright test example.spec.ts:9 --debug
yarn playwright test example.spec.ts:9 --debug
pnpm exec playwright test example.spec.ts:9 --debug
CI 环境调试
对于 CI 环境中的测试失败,建议使用 Playwright 的 trace viewer 替代视频和截图。trace viewer 会将测试的完整追踪记录生成本地渐进式 Web 应用 (PWA),便于分享。通过 trace viewer,您可以查看时间线、使用开发者工具检查每个操作的 DOM 快照、查看网络请求等。

追踪功能在 Playwright 配置文件中配置,默认会在 CI 环境中首次重试失败测试时运行。我们不建议将其设置为 on
来为每次测试都生成追踪,因为这会对性能造成较大影响。但在本地开发时,您可以使用 --trace
标志来运行追踪。
- npm
- yarn
- pnpm
npx playwright test --trace on
yarn playwright test --trace on
pnpm exec playwright test --trace on
运行此命令后,将为每个测试记录追踪信息,并可直接从 HTML 报告中查看。
- npm
- yarn
- pnpm
npx playwright show-report
yarn playwright show-report
pnpm exec playwright show-report

可以通过点击测试文件名旁边的图标来打开追踪记录,或者打开每个测试报告并滚动到追踪记录部分查看。

使用 Playwright 工具链
Playwright 提供了一系列工具来帮助您编写测试:
- VS Code 扩展 在编写、运行和调试测试时提供出色的开发体验
- 测试生成器 可以为您生成测试并选择定位器
- 追踪查看器 以本地 PWA 形式提供完整的测试追踪记录,便于分享。通过追踪查看器,您可以查看时间线、检查每个操作的 DOM 快照、查看网络请求等
- UI 模式 让您能够通过时光旅行体验探索、运行和调试测试,并包含监视模式。所有测试文件都会加载到测试侧边栏中,您可以展开每个文件和描述块来单独运行、查看、监视和调试每个测试
- Playwright 中的 TypeScript 开箱即用,提供更好的 IDE 集成。您的 IDE 会显示所有可用操作,并在出错时高亮提示。无需 TypeScript 经验,您的代码也不必使用 TypeScript,只需使用
.ts
扩展名创建测试即可
跨浏览器测试
Playwright 让您可以轻松地在所有 浏览器 上测试您的网站,无论您使用什么平台。跨浏览器测试确保您的应用对所有用户都可用。在配置文件中,您可以设置项目,添加名称和要使用的浏览器或设备。
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
});
保持 Playwright 依赖项最新
通过保持 Playwright 版本最新,您将能够在最新的浏览器版本上测试您的应用程序,并在最新浏览器版本公开发布前发现问题。
- npm
- yarn
- pnpm
npm install -D @playwright/test@latest
yarn add --dev @playwright/test@latest
pnpm install --save-dev @playwright/test@latest
查看 发布说明 了解最新版本信息及变更内容。
您可以通过以下命令查看当前安装的 Playwright 版本。
- npm
- yarn
- pnpm
npx playwright --version
yarn playwright --version
pnpm exec playwright --version
在 CI 上运行测试
设置 CI/CD 并频繁运行测试。测试运行越频繁越好。理想情况下,应在每次提交和拉取请求时运行测试。Playwright 提供了 GitHub Actions 工作流,无需额外配置即可在 CI 上运行测试。Playwright 也可以配置在您选择的 CI 环境 中运行。
在 CI 上运行测试时使用 Linux 系统,因为成本更低。开发者本地运行时可以使用任何环境,但在 CI 上应使用 Linux。考虑设置 测试分片 来加速 CI 运行。
在 CI 上优化浏览器下载
只安装你实际需要的浏览器,特别是在 CI 环境中。例如,如果只使用 Chromium 进行测试,就只安装 Chromium。
# 替代安装所有浏览器的做法
npx playwright install --with-deps
# 仅安装 Chromium
npx playwright install chromium --with-deps
这样可以节省 CI 机器的下载时间和磁盘空间。
对测试进行代码检查
我们推荐使用 TypeScript 和 ESLint 对测试代码进行静态检查,以便及早发现错误。使用 @typescript-eslint/no-floating-promises
ESLint 规则来确保在调用 Playwright API 的异步方法前没有遗漏 await。在 CI 上可以运行 tsc --noEmit
来确保函数调用使用了正确的签名。
使用并行化和分片执行
Playwright 默认以并行方式运行测试。单个文件中的测试会按顺序在同一个工作进程中运行。如果单个文件中有许多独立的测试,你可能希望并行运行它们:
import { test } from '@playwright/test';
test.describe.configure({ mode: 'parallel' });
test('并行运行测试 1', async ({ page }) => { /* ... */ });
test('并行运行测试 2', async ({ page }) => { /* ... */ });
Playwright 可以分片测试套件,使其能在多台机器上执行。
- npm
- yarn
- pnpm
npx playwright test --shard=1/3
yarn playwright test --shard=1/3
pnpm exec playwright test --shard=1/3
生产力提升技巧
使用软断言
当测试失败时,Playwright 会显示错误信息指出测试的哪部分失败了,你可以在 VS Code、终端、HTML 报告或追踪查看器中看到这些信息。不过,你也可以使用软断言。这些断言不会立即终止测试执行,而是在测试结束后汇总并显示所有失败的断言列表。
// 进行一些检查,即使失败也不会停止测试...
await expect.soft(page.getByTestId('status')).toHaveText('Success');
// ...然后继续测试以检查更多内容。
await page.getByRole('link', { name: 'next page' }).click();