测试重试
测试重试是一种在测试失败时自动重新运行测试的方法。当测试不稳定并间歇性失败时,这很有用。测试重试在配置文件中配置。
失败
Playwright Test 在工作进程中运行测试。这些进程是 OS 进程,独立运行,由测试运行器编排。所有工作进程都有相同的环境,每个都启动自己的浏览器。
考虑以下代码片段:
- TypeScript
- JavaScript
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 }) => { /* ... */ });
});
const { test } = require('@playwright/test');
test.describe('suite', () => {
test.beforeAll(async () => { /* ... */ });
test('first good', async ({ page }) => { /* ... */ });
test('second flaky', async ({ page }) => { /* ... */ });
test('third good', async ({ page }) => { /* ... */ });
});
当所有测试都通过时,它们将在同一工作进程中按顺序运行。
- 工作进程启动
beforeAll钩子运行first good通过second flaky通过third good通过
如果任何测试失败,Playwright Test 将丢弃整个工作进程以及浏览器,并启动一个新的。测试将在新的工作进程中继续,从下一个测试开始。
- 工作进程 #1 启动
beforeAll钩子运行first good通过second flaky失败
- 工作进程 #2 启动
beforeAll钩子再次运行third good通过
如果您启用重试,第二个工作进程将通过重试失败的测试开始,然后从那里继续。
- 工作进程 #1 启动
beforeAll钩子运行first good通过second flaky失败
- 工作进程 #2 启动
beforeAll钩子再次运行second flaky被重试并通过third good通过
这个方案对于独立测试非常有效,并保证失败的测试不会影响健康的测试。
重试
Playwright Test 支持测试重试。启用后,失败的测试将被多次重试,直到它们通过,或直到达到最大重试次数。默认情况下,失败的测试不会被重试。
# 给失败的测试 3 次重试机会
npx playwright test --retries=3
- TypeScript
- JavaScript
// playwright.config.ts
import type { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
// 给失败的测试 3 次重试机会
retries: 3,
};
export default config;
// playwright.config.js
// @ts-check
/** @type {import('@playwright/test').PlaywrightTestConfig} */
const config = {
// 给失败的测试 3 次重试机会
retries: 3,
};
module.exports = config;
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 访问。以下是一个在重试前清除某些服务器端状态的示例。
- TypeScript
- JavaScript
import { test, expect } from '@playwright/test';
test('my test', async ({ page }, testInfo) => {
if (testInfo.retry)
await cleanSomeCachesOnTheServer();
// ...
});
const { test, expect } = require('@playwright/test');
test('my test', async ({ page }, testInfo) => {
if (testInfo.retry)
await cleanSomeCachesOnTheServer();
// ...
});
您可以使用 test.describe.configure([options]) 为特定测试组或单个文件指定重试次数。
- TypeScript
- JavaScript
import { test, expect } from '@playwright/test';
test.describe(() => {
// 此 describe 组中的所有测试将获得 2 次重试机会。
test.describe.configure({ retries: 2 });
test('test 1', async ({ page }) => {
// ...
});
test('test 2', async ({ page }) => {
// ...
});
});
const { test, expect } = require('@playwright/test');
test.describe(() => {
// 此 describe 组中的所有测试将获得 2 次重试机会。
test.describe.configure({ retries: 2 });
test('test 1', async ({ page }) => {
// ...
});
test('test 2', async ({ page }) => {
// ...
});
});
串行模式
使用 test.describe.serial(title, callback) 对依赖测试进行分组,以确保它们始终一起按顺序运行。如果其中一个测试失败,所有后续测试都将被跳过。组中的所有测试将一起重试。
考虑以下使用 test.describe.serial 的代码片段:
- TypeScript
- JavaScript
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 }) => { /* ... */ });
const { test } = require('@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通过
通常最好使您的测试隔离,以便它们可以独立高效地运行和重试。
在测试之间重用单个页面
Playwright Test 为每个测试创建一个隔离的 Page 对象。但是,如果您想在多个测试之间重用单个 Page 对象,可以在 test.beforeAll(hookFunction) 中创建自己的对象,并在 test.afterAll(hookFunction) 中关闭它。
- TypeScript
- JavaScript
// example.spec.ts
import { test, 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();
});
// example.spec.js
// @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();
});