並列処理
イントロダクション
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を活用して、異なるワーカーで実行されるテスト間でデータベース内のユーザーデータを分離できます。ワーカーによって実行されるすべてのテストは同じユーザーを再利用します。
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
ステートメントの順序にテストが依存するようになり、予期しない結果につながる可能性があります。代わりに、上記の例のように、テストリストファイルによって明示的に呼び出される関数でテストをラップしてください。