jestのbeforeEach/Allでasyncを使ってうまくいかなかった場合の備忘録


Jestだと、テストごとに初期化したりDBにモックデータを突っ込んだりする場合にbeforeEachに処理を書きますが、なかなかうまくいかなかったので対処した際の備忘録です。

公式Doc

beforeEach と afterEach は非同期コードをテストする と同様に非同期コードを扱えます - promise を返すか done パラメータのどちらかを選択します。 たとえば、もし initializeCityDatabase() が promiseを返すのであれば、データベースが初期化された際には promise が返されることが望まれます。

beforeEach(() => {
  return initializeCityDatabase();
});

または

beforeEach(async (done) => {
  await initializeCityDatabase();
  done()
});

まずreturnし忘れていないか、done()を書いているかチェック

タイムアウト時間を伸ばす

デフォルトのタイムアウト時間は5000msなので、時間がかかる処理をAsync内で行うと期待どおりに動作しない場合がある。
jest.config.jssetupFilesAfterEnvに指定したファイルで指定するのが良さそう。

jest.setTimeout(10000)

それでも解決しない

手元で起きた問題の場合、どうやら最初に実行されるテストだけがbeforeEachでDBの初期化に失敗してしまうらしく、それ以降のテストは問題ない。
少々強引だが、リトライを設定すればテストは通るはず。

Jestのリトライ設定

Runs failed tests n-times until they pass or until the max number of retries is exhausted. This only works with jest-circus!

テストにおける例:

jest.retryTimes(3);
test('will fail', () => {
  expect(true).toBe(false);
});

This only works with jest-circus!と書かれているのでそのままでは使えない。

jest-circus

軽くて高機能なテストランナーらしい。
デフォルトのテストランナーはjasmine2なので切り替える。

npm i -D jest-circus
jest.config.js
module.exports = {
  ...
  testRunner: 'jest-circus/runner',
  ...
}

リトライが使えるようになり、強引だが一応テストは通るようになった。

根本的に何故うまくいかないのか、こちらで同様の議論があった。
https://github.com/facebook/jest/issues/1256