jest の spy を使ったテストでテスト順番に依存して落ちたり落ちなかったりする問題の解決


spy で toBeCalled() を使ったテストで、テストの順番に依存してうまく動いたり動かなかったりする現象があって、ハマりそうだったので記録しておきます。
テスト対象は TypeScript の関数ですが、型がある以外は JavaScript に読み替えても同じだと思います。

テスト対象の関数が以下のようにあるとします。


export const targetFunction = (flag: boolean) => {
  if (flag) {
    console.error('出力です')
  }
}

失敗するパターンのテスト


import { targetFunction } from '~/plugins/axios'

const spyConsoleError = jest.spyOn(console, 'error')
spyConsoleError.mockImplementation(() => {
})

describe('spy resetの動作テスト', () => {
  test('console error が呼ばれる', async () => {
    await targetFunction(true)

    expect(console.error).toBeCalled()
  })

  test('console error が呼ばれないはず', async () => {
    await targetFunction(false)

    expect(console.error).not.toBeCalled()
  })
})

これを実行してみると

対象のテストの中では console.error は呼ばれていないはずなのですが、すでに前のテストで呼ばれているため、1回呼ばれたことになってしまっています。

うまくいくように書き換えたパターン



import { targetFunction } from '~/plugins/axios'

const spyConsoleError = jest.spyOn(console, 'error')
spyConsoleError.mockImplementation(() => {
})

// ------  これを書き足します --------
beforeEach(() => {
  spyConsoleError.mockReset()
})
// ------  ここまで  ---------

describe('spy resetの動作テスト', () => {
 // 同じテスト
})

それぞれのテストの前に beforeEach で初期化処理をしてあげると依存関係の問題が起こりません。