🎭

Playwrightの並列実行とテストファイルの分け方まとめ方

2022/08/01に公開

最初にまとめ

config.tsでfullyParallelを指定しない場合

  • テストファイルはファイルごとに並列で実行される
  • 一つのテストファイルに複数テストがある場合、モードを指定できる
    • デフォルト: 1つのワーカーで順番に実行される、途中で失敗した場合も後続のテストを実行する
    • パラレル: 複数のワーカーで実行する、途中で失敗した場合も後続のテストを実行する
    • シリアル: 1つのワーカーで上から順番に実行される、途中で失敗した場合は後続のテストをスキップする
  • シリアルはあまりおすすめしない

基本的には他に依存しないテストたちは目的や機能ごとに一つのファイルにまとめてパラレルモードにする。
シリアルモードにするかデフォルトにするかは、前のテストが失敗した時に次のテストやることに意味があるかどうかを考えれば判断できそう。

動機

playwrightでE2Eテストを書いていて、テストをどのファイルに入れたり移動していいか迷うことがあったので、曖昧な部分をスッキリさせたい。
シリアル・パラレルモードもなんとなくイメージしている程度だったので、実際に動かして確認してみたい。

まずはドキュメントを読む

Parametrize tests | Playwright

  • デフォルトでは、テストファイルは並列で実行されます。
  • 一つのファイルに含まれるテストは、同じワーカープロセスで順番に実行されます。
  • テストファイルにパラレルモードにすると、1つのファイル内でも並列で実行される
  • 相互に依存するテストにシリアルとして注釈を付けることができます。
  • シリアルテストの1つが失敗すると、後続のすべてのテストがスキップされます。グループ内のすべてのテストがまとめて再試行されます。

※Google翻訳

確認してみる

準備

$ npm init playwright@latest
npx: 1個のパッケージを2.913秒でインストールしました。
Getting started with writing end-to-end tests with Playwright:
Initializing project in '.'
✔ Do you want to use TypeScript or JavaScript? · TypeScript
✔ Where to put your end-to-end tests? · tests
✔ Add a GitHub Actions workflow? (y/N) · false

$ npx playwright --version
Version 1.24.1

configファイルを修正

playwright.config.ts
  /* Run tests in files in parallel */
  // fullyParallel: true, // ←コメントアウトする

ついでにtests/*.spec.tsを削除します

確認してみる

> デフォルトでは、テストファイルは並列で実行されます。

テストファイルを2つ作って実験してみます。
「並列で実行」されているかはどうやって確認したらいいかわからなかったので、別のワーカーで実行されていたら「並行で実行」されてるっぽいとみなしていきたいと思います。
ワーカーはtestInfo.workerIndexの値で区別していきます。

tests/test1.spec.ts
import { test, expect } from '@playwright/test';

test('test1', ({ }, testInfo) => {
    console.log('test1:' + testInfo.workerIndex)
    expect(true).toBe(true);
})
tests/test2.spec.ts
import { test, expect } from '@playwright/test';

test('test2', ({ }, testInfo) => {
    console.log('test2:' + testInfo.workerIndex)
    expect(true).toBe(true);
})

結果

$npx playwright test --project=chromium --reporter=list

Running 2 tests using 2 workers

  ✓  [chromium] › test1.spec.ts:3:1 › test1 (47ms)
test1:0
  ✓  [chromium] › test2.spec.ts:3:1 › test2 (36ms)
test2:1

workerIndexの値が違うので、別のワーカーで実行されたみたいです。

> 一つのファイルに含まれるテストは、同じワーカープロセスで順番に実行されます。

test1.spec.tsに3つテストを書いて、"同じワーカープロセスで順番に実行"されてるか確認します。
workerIndexが同じでABC順にconsole.logの結果が出力されれば良さそう。

tests/test.spec.ts
import { test, expect } from '@playwright/test';

test('test1A', ({ }, testInfo) => {
    console.log('test1A:' + testInfo.workerIndex)
    expect(true).toBe(true);
})

test('test1B', ({ }, testInfo) => {
    console.log('test1B:' + testInfo.workerIndex)
    expect(true).toBe(true);
})

test('test1C', ({ }, testInfo) => {
    console.log('test1C:' + testInfo.workerIndex)
    expect(true).toBe(true);
})

結果

npx playwright test test1 --project=chromium --reporter=list

Running 3 tests using 1 worker

  ✓  [chromium] › test1.spec.ts:3:1 › test1A (41ms)
test1A:0
  ✓  [chromium] › test1.spec.ts:8:1 › test1B (11ms)
test1B:0
  ✓  [chromium] › test1.spec.ts:13:1 › test1C (5ms)
test1C:0


  3 passed (920ms)

想定通り、workerIndexの値が同じで、ABCの順番に実行されてますね。

> テストファイルにパラレルモードにすると、1つのファイル内でも並列で実行される

mode: 'parallel'にしてみます。

test1.spec.ts
import { test, expect } from '@playwright/test';
test.describe.configure({ mode: 'parallel' });

test('test1A', ({ }, testInfo) => {
    console.log('test1A:' + testInfo.workerIndex)
    expect(true).toBe(true);
})

test('test1B', ({ }, testInfo) => {
    console.log('test1B:' + testInfo.workerIndex)
    expect(true).toBe(true);
})

test('test1C', ({ }, testInfo) => {
    console.log('test1C:' + testInfo.workerIndex)
    expect(true).toBe(true);
})
$ npx playwright test test1 --project=chromium --reporter=list

Running 3 tests using 2 workers

  ✓  [chromium] › test1.spec.ts:4:1 › test1A (162ms)
test1A:0
  ✓  [chromium] › test1.spec.ts:9:1 › test1B (151ms)
test1B:1
  ✓  [chromium] › test1.spec.ts:14:1 › test1C (7ms)
test1C:0


  3 passed (1s)

2つのワーカーが使われました。(using 2 workers)
1つのファイル内でも並列に実行されているみたいですね

> シリアルテストの1つが失敗すると、後続のすべてのテストがスキップされます。

まずはシリアルを実験してみます。
ドキュメントにおすすめしないって書いてありますが、気づいたら増えてそうなやつ…。
2番目の実験と同じ結果になるっぽいですよね。

tests/test1.spec.ts
import { test, expect } from '@playwright/test';
test.describe.configure({ mode: 'serial' }) // 追加

test('test1A', ({ }, testInfo) => {
    console.log('test1A:' + testInfo.workerIndex)
    expect(true).toBe(true);
})

test('test1B', ({ }, testInfo) => {
    console.log('test1B:' + testInfo.workerIndex)
    expect(true).toBe(true);
})

test('test1C', ({ }, testInfo) => {
    console.log('test1C:' + testInfo.workerIndex)
    expect(true).toBe(true);
})

結果

$ npx playwright test test1 --project=chromium --reporter=list

Running 3 tests using 1 worker

  ✓  [chromium] › test1.spec.ts:4:1 › test1A (24ms)
test1A:0
  ✓  [chromium] › test1.spec.ts:9:1 › test1B (3ms)
test1B:0
  ✓  [chromium] › test1.spec.ts:14:1 › test1C (3ms)
test1C:0

同じですね。workerIndexが全部同じでABCの順番で実行されてるっぽいです。

ついでにシリアルだと”1つが失敗すると、後続のすべてのテストがスキップ”されるみたいなので、デフォルトの場合はスキップされないのか確認します。
workerIndexは上で確認したので外します。

import { test, expect } from '@playwright/test';
test.describe.configure({ mode: 'serial' }) // コメントアウト

test('test1A', ({ }, testInfo) => {
    expect(true).toBe(true);
})

test('test1B', ({ }, testInfo) => {
    expect(true).toBe(false); // 失敗させる
})

test('test1C', ({ }, testInfo) => {
    expect(true).toBe(true);
})

結果

(base) ❯ npx playwright test test1 --project=chromium --reporter=list

Running 3 tests using 1 worker

  ✓  [chromium] › test1.spec.ts:4:1 › test1A (26ms)[chromium] › test1.spec.ts:9:1 › test1B (7ms)[chromium] › test1.spec.ts:14:1 › test1C (21ms)

  ...省略...

  1 failed
    [chromium] › test1.spec.ts:9:1 › test1B ========================================================
  2 passed (2s)

シリアルと違い、test1Cのテストがスキップされず実行されました。

次にシリアルで途中で失敗させて後続がskipされてるか確認します。

test1.spec.ts
import { test, expect } from '@playwright/test';
test.describe.configure({ mode: 'serial' }) // シリアルにする

test('test1A', ({ }, testInfo) => {
    expect(true).toBe(true);
})

test('test1B', ({ }, testInfo) => {
    expect(true).toBe(false); // 失敗させる
})

test('test1C', ({ }, testInfo) => {
    expect(true).toBe(true);
})

test1Bが失敗して、後続のtest1Cがスキップされました。

(base) ❯ npx playwright test test1 --project=chromium --reporter=list

Running 3 tests using 1 worker

  ✓  [chromium] › test1.spec.ts:4:1 › test1A (20ms)
test1A:0
  ✘  [chromium] › test1.spec.ts:9:1 › test1B (6ms)
test1B:0
  -  [chromium] › test1.spec.ts:14:1 › test1C

  ...省略...


  1 failed
    [chromium] › test1.spec.ts:9:1 › test1B ========================================================
  1 skipped
  1 passed (712ms)

Discussion