並列処理
はじめに
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,
},
]
});
シリアルモード
相互依存するテストをシリアルとしてアノテーションできます。シリアルテストの 1 つが失敗した場合、後続のすべてのテストはスキップされます。グループ内のすべてのテストはまとめて再試行されます。
シリアルの使用は推奨されません。通常、テストを分離して、独立して実行できるようにする方が良いでしょう。
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();
});
複数マシン間でのテストのシャーディング
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,
});
ワーカーインデックスと並列インデックス
各ワーカープロセスには、1 から始まる一意のワーカーインデックスと、0
から workers - 1
の間の並列インデックスの 2 つの ID が割り当てられます。たとえば、失敗後にワーカーが再起動された場合、新しいワーカープロセスは同じ parallelIndex
と新しい workerIndex
を持ちます。
インデックスは、環境変数 process.env.TEST_WORKER_INDEX
および process.env.TEST_PARALLEL_INDEX
から読み取るか、testInfo.workerIndex および testInfo.parallelIndex を介してアクセスできます。
並列ワーカー間でのテストデータの分離
上記の process.env.TEST_WORKER_INDEX
または testInfo.workerIndex を利用して、異なるワーカーで実行されているテスト間でデータベース内のユーザーデータを分離できます。ワーカーによって実行されるすべてのテストは、同じユーザーを再利用します。
dbUserName
フィクスチャを作成し、テストデータベースに新しいユーザーを初期化する playwright/fixtures.ts
ファイルを作成します。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
ステートメントの順序に依存するようになるため、予期しない結果につながる可能性があります。代わりに、上記の例のように、テストリストファイルによって明示的に呼び出される関数でテストをラップします。