跳至主要内容

最佳实践

简介

本指南应帮助您确保遵循我们的最佳实践,编写更具弹性的测试。

测试理念

测试用户可见行为

自动化测试应该验证应用程序代码对终端用户是否有效,并避免依赖实现细节,比如用户通常不会使用、看到甚至知道的细节,例如函数名称、某个东西是否是数组,或者某些元素的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 Network 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' });

您还可以通过filter locators按文本或其他定位器进行筛选。

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检查器中编辑定位器进行探索,例如修改文本内容,并在浏览器窗口中查看结果。

generating locators with codegen

使用VS Code扩展生成定位器

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

generating locators in vs code with codegen

使用网页优先断言

断言是一种验证预期结果与实际结果是否匹配的方法。通过使用web first assertions,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()这样的网页优先断言来代替。

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

配置调试

本地调试

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

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为您提供完整的测试跟踪记录,以本地渐进式网络应用(PWA)的形式呈现,便于分享。通过trace viewer,您可以查看时间线、使用开发者工具检查每个操作的DOM快照、查看网络请求等更多功能。

playwrights trace viewer

追踪功能在Playwright配置文件中进行设置,并配置为在CI上首次重试失败测试时运行。我们不建议将此设置为on,因为这样会在每次测试时都运行追踪,性能开销很大。不过您可以在本地开发时使用--trace标志来运行追踪。

npx playwright test --trace on

Once you run this command your traces will be recorded for each test and can be viewed directly from the HTML report.

npx playwright show-report
Playwrights HTML report

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

Screenshot 2023-01-13 at 09 58 34

使用Playwright的工具

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

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

跨所有浏览器进行测试

Playwright让您能够轻松地在所有browsers上测试您的网站,无论您使用什么平台。跨所有浏览器进行测试可确保您的应用程序适用于所有用户。在配置文件中,您可以设置项目,添加名称以及要使用的浏览器或设备。

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 workflow,因此测试将在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机器上的下载时间和磁盘空间。

检查你的测试

我们建议在测试中使用TypeScript和ESLint进行代码检查,以便及早发现错误。使用@typescript-eslint/no-floating-promises ESLint规则来确保在异步调用Playwright API之前没有遗漏await。在持续集成环境中,您可以运行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

生产力提升技巧

使用软断言

If your test fails, Playwright will give you an error message showing what part of the test failed which you can see either in VS Code, the terminal, the HTML report, or the trace viewer. However, you can also use soft assertions. These do not immediately terminate the test execution, but rather compile and display a list of failed assertions once the test ended.

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