跳到主要内容

最佳实践

简介​

本指南将帮助您遵循我们的最佳实践,编写更具健壮性的测试用例。

测试理念​

测试用户可见行为​

自动化测试应当验证应用程序代码对终端用户是否正常工作,避免依赖实现细节——即那些用户通常不会使用、看到甚至不知道的内部信息,例如函数名称、某个变量是否为数组、元素的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。

npx playwright codegen playwright.dev

这将打开一个新的浏览器窗口以及 Playwright 检查器。要选择定位器,首先点击"Record"按钮停止录制。默认情况下,当您运行 codegen 命令时,它会开始新的录制。停止录制后,"Pick Locator"按钮将变为可点击状态。

然后您可以在浏览器窗口中悬停页面上的任何元素,光标下方会高亮显示定位器。点击元素会将定位器添加到 Playwright 检查器中。您可以直接复制定位器粘贴到测试文件中,或者继续在 Playwright 检查器中编辑定位器(例如修改文本)并在浏览器窗口中查看结果。

使用 codegen 生成定位器

使用 VS Code 扩展生成定位器​

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

在 VS Code 中使用 codegen 生成定位器

使用 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 中实时调试测试。您可以通过右键点击测试行旁边的空白处来以调试模式运行测试,这将打开浏览器窗口并在设置的断点处暂停。

debugging tests in vscode

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

live debugging locators in vscode

您也可以通过使用 --debug 标志运行测试,通过 Playwright 检查器来调试测试。

npx playwright test --debug

然后您可以逐步执行测试,查看可操作性日志,实时编辑定位器并在浏览器窗口中看到高亮显示。这将展示哪些定位器匹配以及匹配的数量。

debugging with the playwright inspector

要调试特定测试,请在 --debug 标志后添加测试文件名和测试行号。

npx playwright test example.spec.ts:9 --debug

CI 环境调试​

对于 CI 环境中的测试失败,建议使用 Playwright 的 trace viewer 替代视频和截图。trace viewer 会将测试的完整追踪记录生成本地渐进式 Web 应用 (PWA),便于分享。通过 trace viewer,您可以查看时间线、使用开发者工具检查每个操作的 DOM 快照、查看网络请求等。

playwrights trace viewer

追踪功能在 Playwright 配置文件中配置,默认会在 CI 环境中首次重试失败测试时运行。我们不建议将其设置为 on 来为每次测试都生成追踪,因为这会对性能造成较大影响。但在本地开发时,您可以使用 --trace 标志来运行追踪。

npx playwright test --trace on

运行此命令后,将为每个测试记录追踪信息,并可直接从 HTML 报告中查看。

npx playwright show-report
Playwrights HTML report

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

Screenshot 2023-01-13 at 09 58 34

使用 Playwright 工具链​

Playwright 提供了一系列工具来帮助您编写测试:

  • VS Code 扩展 在编写、运行和调试测试时提供出色的开发体验
  • 测试生成器 可以为您生成测试并选择定位器
  • 追踪查看器 以本地 PWA 形式提供完整的测试追踪记录,便于分享。通过追踪查看器,您可以查看时间线、检查每个操作的 DOM 快照、查看网络请求等
  • UI 模式 让您能够通过时光旅行体验探索、运行和调试测试,并包含监视模式。所有测试文件都会加载到测试侧边栏中,您可以展开每个文件和描述块来单独运行、查看、监视和调试每个测试
  • Playwright 中的 TypeScript 开箱即用,提供更好的 IDE 集成。您的 IDE 会显示所有可用操作,并在出错时高亮提示。无需 TypeScript 经验,您的代码也不必使用 TypeScript,只需使用 .ts 扩展名创建测试即可

跨浏览器测试​

Playwright 让您可以轻松地在所有 浏览器 上测试您的网站,无论您使用什么平台。跨浏览器测试确保您的应用对所有用户都可用。在配置文件中,您可以设置项目,添加名称和要使用的浏览器或设备。

playwright.config.ts
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 install -D @playwright/test@latest

查看 发布说明 了解最新版本信息及变更内容。

您可以通过以下命令查看当前安装的 Playwright 版本。

npx playwright --version

在 CI 上运行测试​

设置 CI/CD 并频繁运行测试。测试运行越频繁越好。理想情况下,应在每次提交和拉取请求时运行测试。Playwright 提供了 GitHub Actions 工作流,无需额外配置即可在 CI 上运行测试。Playwright 也可以配置在您选择的 CI 环境 中运行。

在 CI 上运行测试时使用 Linux 系统,因为成本更低。开发者本地运行时可以使用任何环境,但在 CI 上应使用 Linux。考虑设置 测试分片 来加速 CI 运行。

在 CI 上优化浏览器下载​

只安装你实际需要的浏览器,特别是在 CI 环境中。例如,如果只使用 Chromium 进行测试,就只安装 Chromium。

.github/workflows/playwright.yml

# 替代安装所有浏览器的做法
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 可以分片测试套件,使其能在多台机器上执行。

npx 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();