【Jest_48】 jest.useFakeTimers() の使い方は?
Jestのjest.useFakeTimers()【使い方&活用法】
1. そもそもjest.useFakeTimers()とは?
Jestが提供するタイマー関数(setTimeout, setInterval, clearTimeout, clearInterval)のモック機能
本物のタイマーを置き換え、時間を手動で進めることができる
テストの高速化・安定化に必須の機能
2. なぜfake timersが必要か?
通常のタイマーを使うと実際に時間を待つためテストが遅くなる
テスト実行中の非同期挙動を正確に制御したい
タイマーのコールバックがいつ呼ばれるかを明示的に操作したい
3. jest.useFakeTimers() の基本的な使い方
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.useRealTimers();
});
test('setTimeout callback', () => {
const mockFn = jest.fn();
setTimeout(mockFn, 1000);
expect(mockFn).not.toBeCalled();
jest.advanceTimersByTime(1000);
expect(mockFn).toBeCalled();
});jest.useFakeTimers() でタイマーをモック化
jest.advanceTimersByTime(ms) で擬似的に時間を進める
jest.useRealTimers() でモックを解除し、実タイマーに戻す
4. Jestのfake timersの種類(モダンとレガシー)
4-1. レガシー(fake timers)
jest.useFakeTimers('legacy');従来からのfake timers
いくつかのES6機能に非対応で古い挙動がある
4-2. モダン(fake timers)
jest.useFakeTimers('modern');Jest 27以降のデフォルト
@sinonjs/fake-timersを使用し、ES6以降のAPIもサポート
より正確で堅牢
5. タイマーを進めるメソッドまとめ
jest.advanceTimersByTime(ms)
指定時間分だけタイマーを進める
jest.runAllTimers()
保留中の全てのタイマーを即座に実行
jest.runOnlyPendingTimers()
保留中のタイマーのみ実行
jest.clearAllTimers()
保留中のタイマーを全てキャンセル
6. 実践的な使い方例
6-1. setTimeoutのテスト
test('delayed call', () => {
const mockFn = jest.fn();
setTimeout(mockFn, 2000);
// 1秒経過、まだ呼ばれていない
jest.advanceTimersByTime(1000);
expect(mockFn).not.toBeCalled();
// さらに1秒経過で呼ばれる
jest.advanceTimersByTime(1000);
expect(mockFn).toBeCalledTimes(1);
});6-2. setIntervalのテスト
test('interval calls', () => {
const mockFn = jest.fn();
const id = setInterval(mockFn, 1000);
jest.advanceTimersByTime(1000);
expect(mockFn).toHaveBeenCalledTimes(1);
jest.advanceTimersByTime(3000);
expect(mockFn).toHaveBeenCalledTimes(4);
clearInterval(id);
});7. async/awaitと組み合わせた使い方
test('async with timers', async () => {
const mockFn = jest.fn();
setTimeout(mockFn, 1000);
jest.advanceTimersByTime(1000);
// 次のTickまで待つ
await Promise.resolve();
expect(mockFn).toBeCalled();
});8. タイマーのモック解除と再設定
テスト間の影響を防ぐためにbeforeEach/afterEachで使い分けるのが推奨
beforeEach(() => jest.useFakeTimers());
afterEach(() => jest.useRealTimers());9. 注意点・よくあるトラブル
タイマーが動かずテストが失敗する
jest.advanceTimersByTime()やjest.runAllTimers()を呼んでいない
async処理のPromiseが解決されない
await Promise.resolve()で次Tickを待つ
BabelやTransformでタイマー関数が変わる
環境によってはjest.useFakeTimers('modern')を明示的に指定
モックタイマー解除忘れ
テスト間で副作用が出るため、afterEachでjest.useRealTimers()を呼ぶ
10. まとめ
jest.useFakeTimers()
タイマー関数をモック化し、時間制御可能にする
モダンモードがおすすめ
Jest 27以降は'modern'モードでより正確に動作
時間を進めるコマンド
advanceTimersByTimeやrunAllTimersなど多彩な操作
asyncテストとの相性
Promiseの解決タイミングにも注意しつつ使う
モック解除は必須
テストの独立性を保つためにuseRealTimers()で戻す
