重試
簡介
測試重試是一種在測試失敗時自動重新執行測試的方法。當測試不穩定且間歇性失敗時,這非常有用。測試重試在configuration file中配置。
失敗
Playwright Test 在 worker 進程中運行測試。這些進程是 OS 進程,獨立運行,由測試運行器協調。所有 worker 都具有相同的環境,並且每個 worker 都啟動自己的瀏覽器。
考慮以下程式碼片段
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 () => { /* ... */ });
});
當所有測試通過時,它們將在同一個 worker 進程中依序運行。
- Worker 進程啟動
beforeAll
hook 運行first good
通過second flaky
通過third good
通過afterAll
hook 運行
如果任何測試失敗,Playwright Test 將丟棄整個 worker 進程以及瀏覽器,並啟動一個新的進程。測試將在新 worker 進程中繼續,從下一個測試開始。
- Worker 進程 #1 啟動
beforeAll
hook 運行first good
通過second flaky
失敗afterAll
hook 運行
- Worker 進程 #2 啟動
beforeAll
hook 再次運行third good
通過afterAll
hook 運行
如果您啟用重試,第二個 worker 進程將通過重試失敗的測試開始,並從那裡繼續。
- Worker 進程 #1 啟動
beforeAll
hook 運行first good
通過second flaky
失敗afterAll
hook 運行
- Worker 進程 #2 啟動
beforeAll
hook 再次運行second flaky
被重試並通過third good
通過afterAll
hook 運行
此方案非常適用於獨立測試,並保證失敗的測試不會影響健康的測試。
重試
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 在運行時檢測重試,任何測試、hook 或 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 }) => { /* ... */ });
當在沒有重試的情況下運行時,失敗後的所有測試都會被跳過
- Worker 進程 #1
beforeAll
hook 運行first good
通過second flaky
失敗third good
完全被跳過
當在有重試的情況下運行時,所有測試都會一起重試
- Worker 進程 #1
beforeAll
hook 運行first good
通過second flaky
失敗third good
被跳過
- Worker 進程 #2
beforeAll
hook 再次運行first good
再次通過second flaky
通過third good
通過
通常最好使您的測試相互獨立,這樣它們就可以高效地獨立運行和重試。
在測試之間重複使用單個頁面
Playwright Test 為每個測試建立一個隔離的 Page 物件。但是,如果您想在多個測試之間重複使用單個 Page 物件,您可以在 test.beforeAll() 中建立自己的物件,並在 test.afterAll() 中關閉它。
- TypeScript
- JavaScript
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.org.tw/');
});
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.org.tw/');
});
test('runs second', async () => {
await page.getByText('Get Started').click();
});