最佳实践

简介

本指南旨在帮助您确保遵循最佳实践,编写更具韧性的测试。

测试哲学

测试用户可见的行为

自动化测试应该验证应用程序代码是否对最终用户有效,而避免依赖实现细节(例如,用户通常不会使用、看到或知道的内容,比如函数的名称、某个元素是否是数组,或者元素的 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 project】)在测试中复用已登录的状态。这样,您只需要登录一次,然后跳过所有测试中的登录步骤。

避免测试第三方依赖

只测试您可以控制的部分。不要尝试测试指向外部站点或您无法控制的第三方服务器的链接。这样不仅会浪费时间并减慢测试速度,而且您无法控制链接到的页面的内容,或者是否存在 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 命令并跟上您想要挑选定位器的 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 检查器中编辑它,修改文本并查看浏览器窗口中的效果。

image 2024 12 17 10 46 08 209

使用 VS Code 插件生成定位器

您也可以使用 【VS Code 扩展】来生成定位器,并录制测试。VS Code 插件还为编写、运行和调试测试提供了很好的开发体验。

image 2024 12 17 10 46 56 674

使用 Web-first 断言

断言是一种验证预期结果和实际结果是否匹配的方式。通过使用 【Web-first 断言】,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);

使用 Web-first 断言,如 toBeVisible()

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

配置调试

本地调试

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

image 2024 12 17 10 50 47 953

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

image 2024 12 17 10 52 38 602

您还可以通过在运行测试时加上 --debug 标志,使用 Playwright 检查器调试您的测试。

  • npm

  • yarn

  • pnpm

npx playwright test --debug
yarn playwright test --debug
pnpm exec playwright test --debug

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

image 2024 12 17 10 57 15 658

要调试特定的测试,添加测试文件的名称和测试的行号,然后加上 --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 快照、查看网络请求等。

image 2024 12 17 11 01 26 428

在 Playwright 配置文件中可以配置 trace,并设置在 CI 上的第一次重试时运行。我们不推荐在每个测试中都启用 trace,因为这会对性能造成较大影响。不过,在本地开发时,你可以使用 --trace 标志来运行 trace。

  • npm

  • yarn

  • pnpm

npx playwright test --trace on
yarn playwright test --trace on
pnpm exec playwright test --trace on

一旦你运行此命令,所有测试的 trace 将被记录,并且可以直接从 HTML 报告中查看。

  • npm

  • yarn

  • pnpm

npx playwright show-report
yarn playwright show-report
pnpm exec playwright show-report
image 2024 12 17 11 10 31 064

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

image 2024 12 17 11 11 09 406

使用 Playwright 工具

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

  • VS Code 插件:为你提供了很好的开发体验,用于编写、运行和调试测试。

  • 测试生成器:可以为你生成测试并选择定位器。

  • Trace 查看器:为你的测试提供完整的追踪,作为本地的渐进式 Web 应用(PWA),并且容易共享。通过 Trace 查看器,你可以查看时间线,使用开发者工具检查每个操作的 DOM 快照,查看网络请求等。

  • UI 模式:让你在“时光旅行”体验中探索、运行和调试测试,带有观察模式。所有的测试文件都加载到测试侧边栏,你可以展开每个文件和描述块,单独运行、查看、观察和调试每个测试。

  • TypeScript 支持: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

  • 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。考虑设置 Sharding(分片)来加速 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 还支持对测试套件进行分片(sharding),这样它就可以在多台机器上执行。

  • npm

  • yarn

  • pnpm

npx playwright test --shard=1/3
yarn playwright test --shard=1/3
pnpm exec playwright test --shard=1/3

提高生产力的小贴士

使用软断言(Soft assertions)

如果你的测试失败,Playwright 会给出错误信息,显示测试中失败的部分,你可以在 VS Code、终端、HTML 报告或 Trace 查看器中看到这些信息。你还可以使用软断言,它不会立即终止测试的执行,而是会在测试结束时编译并显示失败的断言列表。

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