🍦

【Playwright】expect.softで一つのexpectが失敗した後もテストを続行させる(Soft Assertion)

2023/09/13に公開

はじめに

Playwrightでは、一つのテストの中に複数のassertion(expect)が存在する時、assertionが一つ失敗した時点でテストは失敗となり、後続は実行されません。

多くの場合はこれで困らないのですが、ビジュアルリグレッションテストを横断的にしたい時、たとえば本番環境と開発環境の複数のページを遷移して、それぞれのページのスクリーンショットを比較したい場合など、いちいち最初のエラーで止まってしまうと面倒です。最後にエラーをまとめて捕捉したい...

expectが失敗してもテストを止めずそのまま続行させたい時に使えるのが、expect.softです。

expect.soft

expect.softは以下のような挙動をします。

  • assertionが失敗してもテストを続行する
  • 一つでも失敗したassertionがあれば、テスト全体は失敗になる
  • 失敗したassertionはtest.info().errorsから参照できる

https://playwright.dev/docs/test-assertions#soft-assertions

実際の例を見てみます。

環境

  • MacBook Air (M1, 2020)
  • pnpm: 8.7.5
  • playwright: 1.37.1

サンプルコード

通常のexpect

まず、通常のexpectの場合。

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

test('assertionが失敗した時点で後続の処理はおこなわれない。', () => {
  expect(2 + 2).toBe(5);
  console.log('この行は実行されない。');
  expect(42).toBeTruthy()
});

これを実行すると、最初のexpectで実行が止まり、2番目のexpectは実行されません。


2つ目のexpectは実行されない

expect.softを用いたSoft Assert

続いて以下はどうでしょうか。test.info().errorsも試してみます。

soft_assertion.spec.ts
test('expect.softを使うと、assetionが失敗しても後続の処理がおこなわれる', () => {
  // false
  expect.soft(2 + 2).toBe(5);
  console.log('この行は実行される。')

  // true
  expect.soft(42).toBeTruthy()

  // false
  expect.soft("Big Brother is watching you").toBeFalsy()

  // 失敗したテストの数はtest.info().errorsで取得できる
  // true
  expect(test.info().errors.length).toBe(2);
});

実行すると下記の結果が得られます。


テストはfailとなり、失敗したexpectの内容が一覧で表示されます。

Test Stepsを見ると、それ以外のassertionは通っていることがわかります。

Test Stepsは最後のexpectまで結果が確認できる

おまけ:Jest / Vitestのexpect.softの対応

Playwrightで使えるならJestでも使えるかと思いきや、そうでもなかったので、補遺です。

Jest: 使えない

Jestでは2023年9月12日現在、まだ実装されていないようです。

Feature RequestのIssueが立っていました。

https://github.com/jestjs/jest/issues/13205

Jestではexpectがグローバルで、特定のテストで挙動を変えるのが難しい、とのこと。


Jestでは使えない

Vitest: 使える

一方でVitestでは使えます。

https://vitest.dev/api/expect.html#soft

Feature Request。
https://github.com/vitest-dev/vitest/issues/3435

It also should be easier to implement than in Jest, because our expect is bound to a test.

とあるように、Vitestの場合はexpectが特定のテストにbindされているので実装ができたようです。違いがあるのですね。

Vitestによるサンプルコードも置いておきます。失敗したassertionはtaskから取り出すことができました。

vitest/tests/soft_assertion.spec.ts
test("expect.softを使うと、assetionが失敗しても後続の処理がおこなわれる", ({ task }) => {
  // false
  expect.soft(2 + 2).toBe(5)
  console.log("この行は実行される。")

  // true
  expect.soft(42).toBeTruthy()

  // false
  expect.soft("Big Brother is watching you").toBeFalsy()

  // 失敗したassertionはtaskから取得できる
  // true
  expect(task.result?.errors?.length).toBe(2)
})

おわりに

ということで、expect.softの簡単な紹介でした。

expectの厳しさに耐えられなくなった時、失敗に寛容なexpect.softのやさしさを思い出してください。


サンプルコードは以下のGitHubに置いておきます。
テストの実行にはVSCodeの各フレームワークのテストランナーを用いました。
https://github.com/HosakaKeigo/sample_soft_assertion

Discussion