かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

TypeScript JEST 引数を取る関数のエラーになる場合のテストにハマったメモ

3億年ぶりに JEST を使って引数を取る関数がエラーになる場合のテストケースを書いていてちょいハマったのでメモ

環境
  • jest ^27.5.0
  • ts-jest ^27.1.3
  • typescript ^4.5.5

JEST toThrow(error) でエラーになる場合のテストができる

toThrow() に取れる

  • 正規表現: エラーメッセージがパターンに マッチする か検証します
  • 文字列:エラーメッセージが文字列を含む か検証します
  • error オブジェクト: エラーメッセージがオブジェクトのmessageプロパティと等しいかを検証します
  • errorクラス: errorオブジェクトがそのクラスのインスタンスであるかを検証します

.toThrowError(error?)toThrow(error)エイリアス

function drinkFlavor(flavor) {
  if (flavor == 'octopus') {
    throw new DisgustingFlavorError('yuck, octopus flavor');
  }
}

// test
test('throws on octopus', () => {
  function drinkOctopus() {
    drinkFlavor('octopus');
  }

  // Test that the error message says "yuck" somewhere: these are equivalent
  expect(drinkOctopus).toThrowError(/yuck/);
  expect(drinkOctopus).toThrowError('yuck');

  // Test the exact error message
  expect(drinkOctopus).toThrowError(/^yuck, octopus flavor$/);
  expect(drinkOctopus).toThrowError(new Error('yuck, octopus flavor'));

  // Test that we get a DisgustingFlavorError
  expect(drinkOctopus).toThrowError(DisgustingFlavorError);
});

cf. .toThrow(error?) | Expect · Jest

テストする関数は expect 内で実行される必要がある

引数を取る関数のエラーになる場合のテストをしようと下記のように書いて正しくエラーを取ることができなかった。

const myFunc = (data: string[]) => {
  if (!data.length) {
    throw new Error('Empty data :(');
  }
};

// test
describe('myFunc', () => {
  test('When argument is an empty array, throw error', () => {
    expect(myFunc([])).toThrow();
  });
});

👇 テストを実行

$ npx jest
 FAIL  ./myFunc.test.ts
  myFunc
    ✕ When argument is an empty array, throw error (1 ms)
  ● myFunc › When argument is an empty array, throw error
    Empty data :(
      1 | const myFunc = (data: string[]) => {
      2 |   if (!data.length) {
    > 3 |     throw new Error('Empty data :(');
        |           ^
      4 |   }
      5 | };

エラーが発生している箇所でテストがエラーになっている?

テストしたい関数が先に実行されてしまっているのが原因

エラーの発生は関数が返す値ではないので、expect(myFunc([])) という書き方だと、先に関数が実行されエラーが発生してしまうので expect でエラーをキャッチすることができずテストが落ちてしまっていた。

エラーが発生することのテストはテストする関数を別途関数でラップする必要がある

expect に関数を渡すと実行されるので、エラーの発生する関数を別の関数で囲ってあげれば良い

// test
describe('myFunc', () => {
  test('When argument is an empty array, throw error', () => {
-   expect(myFunc([])).toThrow();
+   expect(() => myFunc([])).toThrow();
  });
});

👇 テストを実行

$ npx jest
 PASS  ./myFunc.test.ts
  myFunc
    ✓ When argument is an empty array, throw error (9 ms)

₍ ᐢ. ̫ .ᐢ ₎ 👌

よくみたら公式のサンプルもテスト用に関数で囲ってた。
教訓。公式のコードはちゃんと見よう。
おわり。


[参考]

作業しながら空挺ドラゴンズのアニメ見返してて、改めて面白いな〜と思って原作買ったら原作の絵が超好みだった。