跳到主要内容

最佳实践

简介

本指南旨在帮助你确保遵循我们的最佳实践并编写更具弹性的测试。

测试理念

测试用户可见的行为

自动化测试应验证应用程序代码对最终用户有效,并避免依赖用户通常不会使用、看到甚至不知道的实现细节,例如函数名、某项是否为数组或某个元素的 CSS 类。最终用户看到或与之交互的是页面上渲染的内容,因此你的测试通常也只应看到/与之交互相同的渲染输出。

使测试尽可能隔离

每个测试都应与其他测试完全隔离,并独立运行,拥有自己的本地存储、会话存储、数据、cookie 等。测试隔离提高了可重现性,使调试更容易,并防止测试失败级联。

为了避免测试中特定部分的重复,你可以使用before 和 after 钩子。在你的测试文件中添加一个 before 钩子,以便在每个测试之前运行一部分测试,例如访问特定的 URL 或登录到应用程序的某个部分。这可以使你的测试保持隔离,因为没有测试依赖于另一个。然而,如果测试足够简单,即使有一点重复也是可以的,特别是如果这能让你的测试更清晰、更容易阅读和维护。

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

test.beforeEach(async ({ page }) => {
// Runs before each test and signs in each 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 }) => {
// page is signed in.
});

test('second', async ({ page }) => {
// page is signed in.
});

你还可以使用setup 项目在测试中重用登录状态。这样你只需登录一次,然后就可以跳过所有测试的登录步骤。

避免测试第三方依赖

只测试你能控制的内容。不要尝试测试不受你控制的外部站点链接或第三方服务器。这不仅耗时且会减慢你的测试速度,而且你无法控制链接页面的内容,也无法控制是否存在可能导致测试失败的 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 有一个测试生成器,可以为你生成测试和选择定位器。它会查看你的页面并找出最佳定位器,优先使用 role、text 和 test id 定位器。如果生成器找到多个匹配的元素,它会改进定位器使其更具弹性并唯一标识目标元素,因此你不必担心因定位器问题导致测试失败。

使用 codegen 生成定位器

要选择定位器,请运行 codegen 命令,后跟你要从中选择定位器的 URL。

npx playwright codegen playwright.dev

这将打开一个新的浏览器窗口以及 Playwright Inspector。要选择定位器,首先点击“录制”按钮停止录制。默认情况下,运行 codegen 命令时会开始新的录制。停止录制后,“选择定位器”按钮将变为可点击。

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

generating locators with codegen

使用 VS Code 扩展生成定位器

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

generating locators in vs code with codegen

使用 Web 优先断言

断言是一种验证预期结果和实际结果是否匹配的方法。通过使用Web 优先断言,Playwright 将等待直到满足预期条件。例如,在测试警告消息时,测试会点击一个按钮,使消息出现,然后检查警告消息是否存在。如果警告消息需要半秒才能出现,像 toBeVisible() 这样的断言会等待并在需要时重试。

// 👍
await expect(page.getByText('welcome')).toBeVisible();

// 👎
expect(await page.getByText('welcome').isVisible()).toBe(true);

不要使用手动断言

不要使用没有等待 expect 的手动断言。在下面的代码中,awaitexpect 内部而不是之前。当使用像 isVisible() 这样的断言时,测试不会等待一秒钟,它只会检查定位器是否存在并立即返回。

// 👎
expect(await page.getByText('welcome').isVisible()).toBe(true);

请改用诸如 toBeVisible() 之类的 Web 优先断言。

// 👍
await expect(page.getByText('welcome')).toBeVisible();

配置调试

本地调试

对于本地调试,我们建议你在 VSCode 中实时调试你的测试,通过安装VS Code 扩展。你可以通过右键点击你要运行的测试旁边的行来在调试模式下运行测试,这将打开一个浏览器窗口并在设置的断点处暂停。

debugging tests in vscode

你可以通过在 VS Code 中点击或编辑测试中的定位器来实时调试你的测试,这将在浏览器窗口中高亮显示此定位器,并显示页面上找到的任何其他匹配的定位器。

live debugging locators in vscode

你还可以通过使用 --debug 标志运行测试来使用 Playwright Inspector 调试你的测试。

npx playwright test --debug

然后,你可以单步执行测试,查看可操作性日志,并实时编辑定位器并在浏览器窗口中看到其高亮显示。这将显示哪些定位器匹配,以及有多少匹配项。

debugging with the playwright inspector

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

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

在 CI 上调试

对于 CI 失败,请使用 Playwright 跟踪查看器代替视频和截图。跟踪查看器提供你测试的完整跟踪,以本地渐进式 Web 应用 (PWA) 的形式,易于共享。使用跟踪查看器,你可以查看时间线,使用开发者工具检查每个操作的 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 模式让你以时间旅行体验探索、运行和调试测试,并带有观察模式。所有测试文件都加载到测试侧边栏中,你可以在其中展开每个文件和 describe 块,单独运行、查看、观察和调试每个测试。
  • 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
# Instead of installing all browsers
npx playwright install --with-deps

# Install only Chromium
npx playwright install chromium --with-deps

这可以节省 CI 机器上的下载时间和磁盘空间。

对你的测试进行 Lint 检查

我们建议为你的测试使用 TypeScript 并通过 ESLint 进行 Lint 检查,以便尽早捕获错误。使用 @typescript-eslint/no-floating-promises ESLint 规则来确保 Playwright API 的异步调用之前没有遗漏 await。在 CI 上,你可以运行 tsc --noEmit 来确保函数以正确的签名调用。

使用并行和分片

Playwright 默认并行运行测试。单个文件中的测试按顺序在同一个工作进程中运行。如果单个文件中有许多独立的测试,你可能希望并行运行它们。

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

test.describe.configure({ mode: 'parallel' });

test('runs in parallel 1', async ({ page }) => { /* ... */ });
test('runs in parallel 2', async ({ page }) => { /* ... */ });

Playwright 可以分片测试套件,以便在多台机器上执行。

npx playwright test --shard=1/3

生产力技巧

使用软断言

如果你的测试失败,Playwright 会提供错误消息显示测试失败的部分,你可以在 VS Code、终端、HTML 报告或跟踪查看器中看到。然而,你也可以使用软断言。它们不会立即终止测试执行,而是在测试结束后编译并显示失败断言的列表。

// Make a few checks that will not stop the test when failed...
await expect.soft(page.getByTestId('status')).toHaveText('Success');

// ... and continue the test to check more things.
await page.getByRole('link', { name: 'next page' }).click();