jest.useFakeTimers()を使ってテスト時間を短縮する
ある外部SDKをラップしたものをjestでテストしたい。 外部のSDKの仕様も相まって、ちょっとややこしかった。
jest.useFakeTimers()
を使ったテストが初めてだったのもあってメモ。
※以下サンプルソースですが、雰囲気コードなので動作しないかも。
SampleSdkという外部のモジュールがあるとする。
// SampleSdk.d.ts interface initContext { type: 'init', body: { isMobile: boolean } } interface getSessionContext { type: 'getSession', body: { token: string } } type Context = initContext | getSessionContext interface Window { // Windowオブジェクトの中にSampleSDKオブジェクトが入っている。 SampleSDK: { dispatch: (context: Context) => void emit: (type: 'init' | 'getSession') => void } }
それをこんな感じでラップする。
// sample.ts class SampleSdk { window: Window emitter: EventTarget promise: null | Promise<initContext['body']> = null constructor(window: Window) { this.window = window // emitterはmittでもなんでもよい、雰囲気で。 this.emitter = window.EventTarget this.init() } async init(): Promise<initContext['body']> { if (this.promise) { return this.promise } const initEvent = new Event('init'), this.window.SampleSDK.dispatch = (context) => { if (context.type === 'init') { this.emitter.dispatchEvent(events[context.type], context.body) } }) this.promise = new Promise(resolve => this.emitter.addEventListener('init', resolve) ) this.window.SampleSDK.emit('init') return this.promise } } // 実際に使うときは // const sdk = new SampleSdk(window) // const body = await sdk.init() // console.log(body) // { isMobile: false }
await SampleSdk.init()で isMobile
が取得できるかテストする
// sampleSdk.spec.ts import SampleSdk from './sampleSdk' describe('SampleSDK', () => { it('初期化完了後デバイス情報が返却されること', () => { const mockWindow = { SampleSdk: { dispatch: () => jest.fn(), emit() { window.setTimeout( () => this.SampleSdk.dispatch({ type: 'init', body: {isMobile: false}}), 1000 ); } }; } new SampleSDk(mockWindow); expect(await this.init()).toEqual({ isMobile: false }) }) })
このままでも一応動くんだけど、テストが完了するまでに絶対1秒かかる。
ので、 jest.useFakeTimers()
と jest.runAllTimers();
を組み合わせることで、
テスト時間を短縮できる。
// sampleSdk.spec.ts import SampleSdk from './sampleSdk' describe('SampleSDK', () => { it('初期化完了後デバイス情報が返却されること', () => { + jest.useFakeTimers(); const mockWindow = { SampleSdk: { dispatch: () => jest.fn(), emit() { window.setTimeout( () => this.SampleSdk.dispatch({ type: 'init', body: {isMobile: false}}), 1000 ); } }; } new SampleSDk(mockWindow); + jest.runAllTimers(); expect(await this.init()).toEqual({ isMobile: false }) }) })