Skip to main content

最佳实践

介绍

¥Introduction

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

¥This guide should help you to make sure you are following our best practices and writing tests that are more resilient.

测试理念

¥Testing philosophy

测试用户可见的行为

¥Test user-visible behavior

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

¥Automated tests should verify that the application code works for the end users, and avoid relying on implementation details such as things which users will not typically use, see, or even know about such as the name of a function, whether something is an array, or the CSS class of some element. The end user will see or interact with what is rendered on the page, so your test should typically only see/interact with the same rendered output.

使测试尽可能隔离

¥Make tests as isolated as possible

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

¥Each test should be completely isolated from another test and should run independently with its own local storage, session storage, data, cookies etc. Test isolation improves reproducibility, makes debugging easier and prevents cascading test failures.

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

¥In order to avoid repetition for a particular part of your test you can use before and after hooks. Within your test file add a before hook to run a part of your test before each test such as going to a particular URL or logging in to a part of your app. This keeps your tests isolated as no test relies on another. However it is also ok to have a little duplication when tests are simple enough especially if it keeps your tests clearer and easier to read and maintain.

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.
});

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

¥You can also reuse the signed-in state in the tests with setup project. That way you can log in only once and then skip the log in step for all of the tests.

避免测试第三方依赖

¥Avoid testing third-party dependencies

只测试你控制的内容。不要尝试测试指向你无法控制的外部站点或第三方服务器的链接。这不仅耗时且会减慢测试速度,而且你无法控制链接到的页面的内容,或者是否存在 cookie 横幅或覆盖页面或任何其他可能导致测试失败的内容。

¥Only test what you control. Don't try to test links to external sites or third party servers that you do not control. Not only is it time consuming and can slow down your tests but also you cannot control the content of the page you are linking to, or if there are cookie banners or overlay pages or anything else that might cause your test to fail.

相反,请使用 Playwright 网络 API 并保证所需的响应。

¥Instead, use the Playwright Network API and guarantee the response needed.

await page.route('**/api/fetch_data_third_party_dependency', route => route.fulfill({
status: 200,
body: testData,
}));
await page.goto('https://example.com');

使用数据库进行测试

¥Testing with a database

如果使用数据库,请确保你控制数据。针对暂存环境进行测试并确保它不会改变。对于视觉回归测试,请确保操作系统和浏览器版本相同。

¥If working with a database then make sure you control the data. Test against a staging environment and make sure it doesn't change. For visual regression tests make sure the operating system and browser versions are the same.

最佳实践

¥Best Practices

使用定位器

¥Use locators

为了编写端到端测试,我们需要首先找到网页上的元素。我们可以使用 locators 中内置的 Playwright 来做到这一点。定位器具有自动等待和重试能力。自动等待意味着 Playwright 对元素执行一系列可操作性检查,例如确保元素在执行单击之前可见并启用。为了使测试具有弹性,我们建议优先考虑面向用户的属性和显式契约。

¥In order to write end to end tests we need to first find elements on the webpage. We can do this by using Playwright's built in locators. Locators come with auto waiting and retry-ability. Auto waiting means that Playwright performs a range of actionability checks on the elements, such as ensuring the element is visible and enabled before it performs the click. To make tests resilient, we recommend prioritizing user-facing attributes and explicit contracts.

// 👍
page.getByRole('button', { name: 'submit' });

使用链接和过滤

¥Use chaining and filtering

定位器可以是 chained,以将搜索范围缩小到页面的特定部分。

¥Locators can be chained to narrow down the search to a particular part of the page.

const product = page.getByRole('listitem').filter({ hasText: 'Product 2' });

你还可以通过文本或其他定位器 过滤定位器

¥You can also filter locators by text or by another locator.

await page
.getByRole('listitem')
.filter({ hasText: 'Product 2' })
.getByRole('button', { name: 'Add to cart' })
.click();

优先选择面向用户的属性而不是 XPath 或 CSS 选择器

¥Prefer user-facing attributes to XPath or CSS selectors

你的 DOM 可以轻松更改,因此让你的测试依赖于 DOM 结构可能会导致测试失败。例如,考虑通过其 CSS 类选择此按钮。如果设计者改变一些东西,那么类可能会改变,破坏你的测试。

¥Your DOM can easily change so having your tests depend on your DOM structure can lead to failing tests. For example consider selecting this button by its CSS classes. Should the designer change something then the class might change breaking your test.

// 👎
page.locator('button.buttonIcon.episode-actions-later');

使用能够适应 DOM 变化的定位器。

¥Use locators that are resilient to changes in the DOM.

// 👍
page.getByRole('button', { name: 'submit' });

生成定位器

¥Generate locators

Playwright 有一个 测试生成器,可以为你生成测试并选择定位器。它将查看你的页面并找出最佳定位器,确定角色、文本和测试 ID 定位器的优先级。如果生成器找到多个与定位器匹配的元素,它将改进定位器,使其具有弹性并唯一标识目标元素,因此你不必担心由于定位器而导致测试失败。

¥Playwright has a test generator that can generate tests and pick locators for you. It will look at your page and figure out the best locator, prioritizing role, text and test id locators. If the generator finds multiple elements matching the locator, it will improve the locator to make it resilient and uniquely identify the target element, so you don't have to worry about failing tests due to locators.

使用 codegen 生成定位器

¥Use codegen to generate locators

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

¥To pick a locator run the codegen command followed by the URL that you would like to pick a locator from.

npx playwright codegen playwright.dev

这将打开一个新的浏览器窗口以及 Playwright 检查器。要选择定位器,请先单击 '记录' 按钮停止录制。默认情况下,当你运行 codegen 命令时,它将开始新的录制。停止录制后,即可单击 '挑选定位器' 按钮。

¥This will open a new browser window as well as the Playwright inspector. To pick a locator first click on the 'Record' button to stop the recording. By default when you run the codegen command it will start a new recording. Once you stop the recording the 'Pick Locator' button will be available to click.

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

¥You can then hover over any element on your page in the browser window and see the locator highlighted below your cursor. Clicking on an element will add the locator into the Playwright inspector. You can either copy the locator and paste into your test file or continue to explore the locator by editing it in the Playwright Inspector, for example by modifying the text, and seeing the results in the browser window.

generating locators with codegen

使用 VS Code 扩展生成定位器

¥Use the VS Code extension to generate locators

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

¥You can also use the VS Code Extension to generate locators as well as record a test. The VS Code extension also gives you a great developer experience when writing, running, and debugging tests.

generating locators in vs code with codegen

使用网络优先断言

¥Use web first assertions

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

¥Assertions are a way to verify that the expected result and the actual result matched or not. By using web first assertions Playwright will wait until the expected condition is met. For example, when testing an alert message, a test would click a button that makes a message appear and check that the alert message is there. If the alert message takes half a second to appear, assertions such as toBeVisible() will wait and retry if needed.

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

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

不要使用手动断言

¥Don't use manual assertions

不要使用不等待期望的手动断言。在下面的代码中,await 位于 expect 内部而不是之前。当使用诸如 isVisible() 之类的断言时,测试不会等待一秒钟,它只会检查定位器是否存在并立即返回。

¥Don't use manual assertions that are not awaiting the expect. In the code below the await is inside the expect rather than before it. When using assertions such as isVisible() the test won't wait a single second, it will just check the locator is there and return immediately.

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

请改用网络优先断言,例如 toBeVisible()

¥Use web first assertions such as toBeVisible() instead.

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

配置调试

¥Configure debugging

本地调试

¥Local debugging

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

¥For local debugging we recommend you debug your tests live in VSCode. by installing the VS Code extension. You can run tests in debug mode by right clicking on the line next to the test you want to run which will open a browser window and pause at where the breakpoint is set.

debugging tests in vscode

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

¥You can live debug your test by clicking or editing the locators in your test in VS Code which will highlight this locator in the browser window as well as show you any other matching locators found on the page.

live debugging locators in vscode

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

¥You can also debug your tests with the Playwright inspector by running your tests with the --debug flag.

npx playwright test --debug

然后,你可以逐步完成测试、查看可操作性日志并实时编辑定位器,并在浏览器窗口中查看它高亮的情况。这将向你显示哪些定位器匹配,有多少个。

¥You can then step through your test, view actionability logs and edit the locator live and see it highlighted in the browser window. This will show you which locators match, how many of them there are.

debugging with the playwright inspector

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

¥To debug a specific test add the name of the test file and the line number of the test followed by the --debug flag.

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

CI 调试

¥Debugging on CI

对于 CI 失败,请使用 Playwright 跟踪查看器 而不是视频和屏幕截图。跟踪查看器为你提供测试的完整跟踪,作为可以轻松共享的本地渐进式 Web 应用 (PWA)。通过跟踪查看器,你可以查看时间线、使用开发工具检查每个操作的 DOM 快照、查看网络请求等。

¥For CI failures, use the Playwright trace viewer instead of videos and screenshots. The trace viewer gives you a full trace of your tests as a local Progressive Web App (PWA) that can easily be shared. With the trace viewer you can view the timeline, inspect DOM snapshots for each action using dev tools, view network requests and more.

playwrights trace viewer

跟踪在 Playwright 配置文件中配置,并设置为在失败测试的第一次重试时在 CI 上运行。我们不建议将其设置为 on,以便在每个测试上运行跟踪,因为它对性能要求很高。但是,在使用 --trace 标志进行开发时,你可以在本地运行跟踪。

¥Traces are configured in the Playwright config file and are set to run on CI on the first retry of a failed test. We don't recommend setting this to on so that traces are run on every test as it's very performance heavy. However you can run a trace locally when developing with the --trace flag.

npx playwright test --trace on

运行此命令后,每次测试的跟踪都会被记录下来,并且可以直接从 HTML 报告中查看。

¥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

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

¥Traces can be opened by clicking on the icon next to the test file name or by opening each of the test reports and scrolling down to the traces section.

Screenshot 2023-01-13 at 09 58 34

使用 Playwright 的工具

¥Use Playwright's Tooling

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

¥Playwright comes with a range of tooling to help you write tests.

  • VS Code 扩展 在编写、运行和调试测试时为你提供出色的开发体验。

    ¥The VS Code extension gives you a great developer experience when writing, running, and debugging tests.

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

    ¥The test generator can generate tests and pick locators for you.

  • 跟踪查看器 作为本地 PWA 为你提供测试的完整跟踪,并且可以轻松共享。使用跟踪查看器,你可以查看时间线、检查每个操作的 DOM 快照、查看网络请求等等。

    ¥The trace viewer gives you a full trace of your tests as a local PWA that can easily be shared. With the trace viewer you can view the timeline, inspect DOM snapshots for each action, view network requests and more.

  • 用户界面模式 让你可以探索、运行和调试测试,并通过监视模式获得完整的时间旅行体验。所有测试文件都加载到测试侧栏中,你可以在其中展开每个文件并描述块以单独运行、查看、观察和调试每个测试。

    ¥The UI Mode lets you explore, run and debug tests with a time travel experience complete with watch mode. All test files are loaded into the testing sidebar where you can expand each file and describe block to individually run, view, watch and debug each test.

  • Playwright 中的 TypeScript 开箱即用,为你提供更好的 IDE 集成。你的 IDE 将向你显示你可以执行的所有操作,并在你做错时高亮。不需要 TypeScript 经验,你的代码也不需要使用 TypeScript,你所需要做的就是使用 .ts 扩展创建测试。

    ¥TypeScript in Playwright works out of the box and gives you better IDE integrations. Your IDE will show you everything you can do and highlight when you do something wrong. No TypeScript experience is needed and it is not necessary for your code to be in TypeScript, all you need to do is create your tests with a .ts extension.

在所有浏览器上进行测试

¥Test across all browsers

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

¥Playwright makes it easy to test your site across all browsers no matter what platform you are on. Testing across all browsers ensures your app works for all users. In your config file you can set up projects adding the name and which browser or device to use.

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 依赖保持最新状态

¥Keep your Playwright dependency up to date

通过保持你的 Playwright 版本为最新,你将能够在最新的浏览器版本上测试你的应用,并在最新的浏览器版本向公众发布之前捕获故障。

¥By keeping your Playwright version up to date you will be able to test your app on the latest browser versions and catch failures before the latest browser version is released to the public.

npm install -D @playwright/test@latest

检查 发行说明 以了解最新版本是什么以及已发布哪些更改。

¥Check the release notes to see what the latest version is and what changes have been released.

你可以通过运行以下命令查看你拥有的 Playwright 版本。

¥You can see what version of Playwright you have by running the following command.

npx playwright --version

在 CI 上运行测试

¥Run tests on CI

设置 CI/CD 并经常运行测试。运行测试的次数越多越好。理想情况下,你应该对每个提交和拉取请求运行测试。Playwright 附带了 GitHub actions 工作流程,因此无需设置即可在 CI 上运行测试。Playwright 也可以设置在你选择的 CI 环境 上。

¥Setup CI/CD and run your tests frequently. The more often you run your tests the better. Ideally you should run your tests on each commit and pull request. Playwright comes with a GitHub actions workflow so that tests will run on CI for you with no setup required. Playwright can also be setup on the CI environment of your choice.

在 CI 上运行测试时使用 Linux,因为它更便宜。开发者在本地运行时可以使用任何环境,但在 CI 上使用 linux。考虑设置 分片 以加快 CI 速度。

¥Use Linux when running your tests on CI as it is cheaper. Developers can use whatever environment when running locally but use linux on CI. Consider setting up Sharding to make CI faster.

检查你的测试

¥Lint your tests

我们建议在测试中使用 TypeScript 和 ESLint 进行 linting,以便尽早发现错误。使用 @typescript-eslint/no-floating-promises ESLint 规则确保在异步调用 Playwright API 之前没有丢失等待。在你的 CI 上,你可以运行 tsc --noEmit 以确保使用正确的签名调用函数。

¥We recommend TypeScript and linting with ESLint for your tests to catch errors early. Use @typescript-eslint/no-floating-promises ESLint rule to make sure there are no missing awaits before the asynchronous calls to the Playwright API. On your CI you can run tsc --noEmit to ensure that functions are called with the right signature.

使用并行性和分片

¥Use parallelism and sharding

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

¥Playwright runs tests in parallel by default. Tests in a single file are run in order, in the same worker process. If you have many independent tests in a single file, you might want to run them in parallel

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 可以 shard 一个测试套件,以便它可以在多台机器上执行。

¥Playwright can shard a test suite, so that it can be executed on multiple machines.

npx playwright test --shard=1/3

生产力技巧

¥Productivity tips

使用软断言

¥Use Soft assertions

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

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