並列処理
はじめに
Playwright Test はテストを並行して実行します。これを実現するために、同時に動作する複数のワーカープロセスを実行します。デフォルトでは、テストファイルが並列で実行されます。単一ファイル内のテストは、同じワーカープロセス内で順次実行されます。
test.describe.configureを使用して、単一ファイル内のテストを並列で実行するように設定できます。- testProject.fullyParallel または testConfig.fullyParallel を使用して、プロジェクト全体のすべてのファイルのすべてのテストを並列で実行するように設定できます。
- 並列実行を無効にするには、ワーカー数を1に制限します。
効率化のために、並列ワーカープロセスの数を制御したり、テストスイート全体の失敗数を制限したりすることができます。
ワーカープロセス
すべてのテストはワーカープロセスで実行されます。これらのプロセスはOSプロセスであり、独立して動作し、テストランナーによって調整されます。すべてのワーカーは同一の環境を持ち、それぞれ独自のブラウザを起動します。
ワーカー間での通信はできません。Playwright Test はテストを高速化するために、可能な限り単一のワーカーを再利用するため、通常、複数のテストファイルが単一のワーカーで順番に実行されます。
後続のテストのためにクリーンな環境を保証するため、テストが失敗するとワーカーは常にシャットダウンされます。
ワーカーを制限する
コマンドラインまたは設定ファイルを介して、並列ワーカープロセスの最大数を制御できます。
コマンドラインから
npx playwright test --workers 4
設定ファイルで
import { defineConfig } from '@playwright/test';
export default defineConfig({
// Limit the number of workers on CI, use default locally
workers: process.env.CI ? 2 : undefined,
});
並列実行を無効にする
いつでも単一のワーカーのみを許可することで、並列実行を無効にできます。設定ファイルで workers: 1 オプションを設定するか、コマンドラインに --workers=1 を渡します。
npx playwright test --workers=1
単一ファイル内のテストを並列化する
デフォルトでは、単一ファイル内のテストは順番に実行されます。単一ファイル内に多数の独立したテストがある場合、test.describe.configure() を使用してそれらを並列で実行したい場合があります。
並列テストは別のワーカープロセスで実行され、状態やグローバル変数を共有できないことに注意してください。各テストは、beforeAll および afterAll を含む、関連するすべてのフックをそれ自体のみに実行します。
import { test } from '@playwright/test';
test.describe.configure({ mode: 'parallel' });
test('runs in parallel 1', async ({ page }) => { /* ... */ });
test('runs in parallel 2', async ({ page }) => { /* ... */ });
または、設定ファイルでこの完全並列モードにすべてのテストをオプトインすることもできます。
import { defineConfig } from '@playwright/test';
export default defineConfig({
fullyParallel: true,
});
いくつかのプロジェクトのみに完全並列モードをオプトインすることもできます。
import { defineConfig } from '@playwright/test';
export default defineConfig({
// runs all tests in all files of a specific project in parallel
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
fullyParallel: true,
},
]
});
シリアルモード
相互依存するテストをシリアルとしてアノテーションできます。シリアルテストのいずれかが失敗した場合、後続のすべてのテストはスキップされます。グループ内のすべてのテストは一緒に再試行されます。
シリアルの使用は推奨されません。通常は、テストを分離して、独立して実行できるようにする方が良いです。
import { test, type Page } from '@playwright/test';
// Annotate entire file as serial.
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.dokyumento.jp/');
});
test('runs second', async () => {
await page.getByText('Get Started').click();
});
完全並列モードをオプトアウトする
設定が testConfig.fullyParallel を使用してすべてのテストに並列モードを適用する場合でも、一部のテストをデフォルト設定で実行したい場合があります。describe ごとにモードをオーバーライドできます。
test.describe('runs in parallel with other describes', () => {
test.describe.configure({ mode: 'default' });
test('in order 1', async ({ page }) => {});
test('in order 2', async ({ page }) => {});
});
複数のマシン間でテストをシャードする
Playwright Test はテストスイートをシャードできるため、複数のマシンで実行できます。詳細については、シャードガイドを参照してください。
npx playwright test --shard=2/3
失敗を制限して高速に失敗する
maxFailures 設定オプションを設定するか、--max-failures コマンドラインフラグを渡すことで、テストスイート全体の失敗数を制限できます。
"最大失敗数" を設定して実行すると、Playwright Test はこの数の失敗したテストに達した後に停止し、まだ実行されていないテストはスキップされます。これは、壊れたテストスイートでリソースを無駄にするのを避けるのに役立ちます。
コマンドラインオプションを渡す
npx playwright test --max-failures=10
設定ファイルでの設定
import { defineConfig } from '@playwright/test';
export default defineConfig({
// Limit the number of failures on CI to save resources
maxFailures: process.env.CI ? 10 : undefined,
});
ワーカーインデックスと並列インデックス
各ワーカープロセスには2つのIDが割り当てられます。1から始まる一意のワーカーインデックスと、0 から workers - 1 までの並列インデックスです。ワーカーが再起動された場合(例えば、失敗後)、新しいワーカープロセスは同じ parallelIndex と新しい workerIndex を持ちます。
インデックスは環境変数 process.env.TEST_WORKER_INDEX および process.env.TEST_PARALLEL_INDEX から読み取るか、testInfo.workerIndex および testInfo.parallelIndex を介してアクセスできます。
並列ワーカー間でテストデータを分離する
上記の process.env.TEST_WORKER_INDEX または testInfo.workerIndex を活用して、異なるワーカーで実行されるテスト間のデータベース内のユーザーデータを分離できます。ワーカーによって実行されるすべてのテストは同じユーザーを再利用します。
playwright/fixtures.ts ファイルを作成して、dbUserName フィクスチャを作成し、テストデータベースに新しいユーザーを初期化します。testInfo.workerIndex を使用してワーカーを区別します。
import { test as baseTest, expect } from '@playwright/test';
// Import project utils for managing users in the test database.
import { createUserInTestDatabase, deleteUserFromTestDatabase } from './my-db-utils';
export * from '@playwright/test';
export const test = baseTest.extend<{}, { dbUserName: string }>({
// Returns db user name unique for the worker.
dbUserName: [async ({ }, use) => {
// Use workerIndex as a unique identifier for each worker.
const userName = `user-${test.info().workerIndex}`;
// Initialize user in the database.
await createUserInTestDatabase(userName);
await use(userName);
// Clean up after the tests are done.
await deleteUserFromTestDatabase(userName);
}, { scope: 'worker' }],
});
これで、各テストファイルは @playwright/test の代わりにフィクスチャファイルから test をインポートする必要があります。
// Important: import our fixtures.
import { test, expect } from '../playwright/fixtures';
test('test', async ({ dbUserName }) => {
// Use the user name in the test.
});
テストの順序を制御する
Playwright Test は、単一ファイル内のテストを並列化しない限り、宣言順に単一ファイルからテストを実行します。
Playwright Test はデフォルトでテストファイルを並列で実行するため、ファイル間のテスト実行順序は保証されません。ただし、並列実行を無効にすると、ファイルをアルファベット順に名前を付けたり、「テストリスト」ファイルを使用したりすることでテスト順序を制御できます。
テストファイルをアルファベット順にソートする
並列テスト実行を無効にすると、Playwright Test はテストファイルをアルファベット順に実行します。001-user-signin-flow.spec.ts、002-create-new-document.spec.ts のように、命名規則を使用してテスト順序を制御できます。
「テストリスト」ファイルを使用する
テストリストは推奨されず、ベストエフォートのみでサポートされています。VS Code 拡張機能やトレーシングなどの一部の機能は、テストリストでは正しく機能しない場合があります。
複数のファイルにヘルパー関数としてテストを配置できます。テストがファイルに直接定義されず、ラッパー関数に定義されている次の例を考えてみましょう。
import { test, expect } from '@playwright/test';
export default function createTests() {
test('feature-a example test', async ({ page }) => {
// ... test goes here
});
}
import { test, expect } from '@playwright/test';
export default function createTests() {
test.use({ viewport: { width: 500, height: 500 } });
test('feature-b example test', async ({ page }) => {
// ... test goes here
});
}
テストの順序を制御するテストリストファイルを作成できます。まず feature-b テストを実行し、次に feature-a テストを実行します。各テストファイルが、テストが定義されている関数を呼び出す test.describe() ブロックでラップされていることに注目してください。これにより、test.use() の呼び出しは単一ファイルからのテストのみに影響します。
import { test } from '@playwright/test';
import featureBTests from './feature-b.spec.ts';
import featureATests from './feature-a.spec.ts';
test.describe(featureBTests);
test.describe(featureATests);
次に、ワーカーを1に設定して並列実行を無効にし、テストリストファイルを指定します。
import { defineConfig } from '@playwright/test';
export default defineConfig({
workers: 1,
testMatch: 'test.list.ts',
});
ヘルパーファイルに直接テストを定義しないでください。これは、テストが import/require ステートメントの順序に依存するようになるため、予期しない結果につながる可能性があります。代わりに、上記の例のように、テストをテストリストファイルによって明示的に呼び出される関数でラップしてください。