Jestで無限ループ処理をテストするときにループから抜けられなくて困ったのでメモ。
参考までにこの記事では脱出手段のある無限ループを想定しています。
目次
確認環境
Env | Ver |
---|---|
@types/jest | 29.5.7 |
jest | 29.7.0 |
typescript | 5.2.2 |
サンプルコード
テスト対象のコード
いわゆるイベントループやメッセージループと言われる類のものです。
import { getHandle } from './lib/get-handle';
export const main = () => {
for (;;) {
const handle = getHandle();
if (handle === 'Click') {
console.log('click');
} else if (handle === 'KeyDown') {
console.log('keydown');
} else {
break;
}
}
};
テストコード
.mockReturnValue()
ではなく.mockReturnValueOnce()
を使うのが肝です。
.mockReturnValue()
だと同じ値が毎回返るので無限ループから抜けられませんが、.mockReturnValueOnce()
は一回だけなので抜けられます。チェーンすると二回目、三回目の返り値も設定できます。
なお、以下の例では.mockReturnValueOnce()
をチェーンさせていますが、させなくてもテストとしては正常に動作します。指定がない場合はundefined
が返るようです。(基本的には明示的に指定しておいた方が良いと考えています。
import { main } from '.';
import * as getHndl from './lib/get-handle';
jest.mock('./lib/get-handle');
describe('main', () => {
it('Clickイベントの分岐に入ること', () => {
jest
.spyOn(getHndl, 'getHandle')
.mockReturnValueOnce('Click')
.mockReturnValueOnce('');
const spiedConsoleLog = jest.spyOn(console, 'log');
main();
expect(spiedConsoleLog).toHaveBeenCalledWith('click');
});
});
余談
.toHaveBeenCalledWith()
は.toEqual()
と同じロジックで判定しているらしいので、.toStrictEqual()
版もあると便利な気がしました。気が向いたらPR出してみようかな…。