重试
失败
Playwright Test 在工作进程中运行测试。这些进程是操作系统进程,独立运行,由测试运行器进行调度。所有工作进程具有相同的环境,并且每个进程启动自己的浏览器。
考虑以下代码示例:
import { test } from '@playwright/test';
test.describe('suite', () => {
test.beforeAll(async () => { /* ... */ });
test('first good', async ({ page }) => { /* ... */ });
test('second flaky', async ({ page }) => { /* ... */ });
test('third good', async ({ page }) => { /* ... */ });
test.afterAll(async () => { /* ... */ });
});
当 所有测试都通过 时,它们将按顺序在同一工作进程中运行。
-
工作进程启动
-
beforeAll 钩子运行
-
first good 通过
-
second flaky 通过
-
third good 通过
-
afterAll 钩子运行
-
如果 任何测试失败,Playwright Test 将丢弃整个工作进程以及浏览器,并启动一个新的工作进程。测试将从下一个测试开始继续。
-
工作进程 #1 启动
-
beforeAll 钩子运行
-
first good 通过
-
second flaky 失败
-
afterAll 钩子运行
-
-
工作进程 #2 启动
-
beforeAll 钩子再次运行
-
third good 通过
-
afterAll 钩子运行
-
如果 启用重试,第二个工作进程将通过重试失败的测试并继续执行:
-
工作进程 #1 启动
-
beforeAll 钩子运行
-
first good 通过
-
second flaky 失败
-
afterAll 钩子运行
-
-
工作进程 #2 启动
-
beforeAll 钩子再次运行
-
second flaky 被重试并通过
-
third good 通过
-
afterAll 钩子运行
-
这种方案适用于独立的测试,并保证失败的测试不会影响健康的测试。
重试
Playwright 支持 测试重试。当启用时,失败的测试将会被重试,直到通过或达到最大重试次数。默认情况下,失败的测试不会被重试。
命令行启用重试:
# Give failing tests 3 retry attempts
npx playwright test --retries=3
你也可以在配置文件中配置重试:
import { defineConfig } from '@playwright/test';
export default defineConfig({
// Give failing tests 3 retry attempts
retries: 3,
});
Playwright Test 将测试分类如下:
-
"passed" - 第一次运行时通过的测试;
-
"flaky" - 第一次运行失败,但重试时通过的测试;
-
"failed" - 第一次运行和所有重试都失败的测试。
Running 3 tests using 1 worker
✓ example.spec.ts:4:2 › first passes (438ms)
x example.spec.ts:5:2 › second flaky (691ms)
✓ example.spec.ts:5:2 › second flaky (522ms)
✓ example.spec.ts:6:2 › third passes (932ms)
1 flaky
example.spec.ts:5:2 › second flaky
2 passed (4s)
你可以通过 testInfo.retry 来在运行时检测重试次数,它可以在任何测试、钩子或 fixture 中访问。以下是一个在重试前清除服务器端状态的例子:
import { test, expect } from '@playwright/test';
test('my test', async ({ page }, testInfo) => {
if (testInfo.retry)
await cleanSomeCachesOnTheServer();
// ...
});
你可以为特定的测试组或单个文件指定重试次数,使用 test.describe.configure():
import { test, expect } from '@playwright/test';
test.describe(() => {
// All tests in this describe group will get 2 retry attempts.
test.describe.configure({ retries: 2 });
test('test 1', async ({ page }) => {
// ...
});
test('test 2', async ({ page }) => {
// ...
});
});
串行模式
使用 test.describe.serial() 将相关的测试分组,以确保它们总是按顺序一起运行。如果其中一个测试失败,所有后续的测试都会被跳过。所有组内的测试将一起重试。
考虑以下代码示例,使用 test.describe.serial():
import { test } from '@playwright/test';
test.describe.configure({ mode: 'serial' });
test.beforeAll(async () => { /* ... */ });
test('first good', async ({ page }) => { /* ... */ });
test('second flaky', async ({ page }) => { /* ... */ });
test('third good', async ({ page }) => { /* ... */ });
如果不使用重试,所有失败后的测试将被跳过:
-
工作进程 #1:
-
beforeAll 钩子运行
-
first good 通过
-
second flaky 失败
-
third good 被完全跳过
-
如果使用重试,所有测试将一起重试:
-
工作进程 #1:
-
beforeAll 钩子运行
-
first good 通过
-
second flaky 失败
-
third good 被跳过
-
-
工作进程 #2:
-
beforeAll 钩子再次运行
-
first good 再次通过
-
second flaky 通过
-
third good 通过
-
通常,最好让测试相互独立,这样可以更高效地运行和重试。 |
在多个测试之间重用同一个 Page 对象
Playwright Test 为每个测试创建一个隔离的 【Page】 对象。然而,如果你希望在多个测试之间重用一个 【Page】 对象,可以在 test.beforeAll() 中创建它,并在 test.afterAll() 中关闭它。
import { test, type Page } from '@playwright/test';
test.describe.configure({ mode: 'serial' });
let page: Page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
});
test.afterAll(async () => {
await page.close();
});
test('runs first', async () => {
await page.goto('https://playwright.dev/');
});
test('runs second', async () => {
await page.getByText('Get Started').click();
});
// @ts-check
const { test } = require('@playwright/test');
test.describe.configure({ mode: 'serial' });
/** @type {import('@playwright/test').Page} */
let page;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
});
test.afterAll(async () => {
await page.close();
});
test('runs first', async () => {
await page.goto('https://playwright.dev/');
});
test('runs second', async () => {
await page.getByText('Get Started').click();
});