画面のテストコードを書いている時に、画面を閉じた時やスリープした時に発生するイベントのコールバック関数の動作をテストしたい時があるかと思います。
そんな時にどうテストを書いたら良いかを以下にサンプルコードを交えながら備忘録として残していきます。
技術 ・React ・ReactTestingLibrary ・jest
まずは以下のような実装があるとします。
・・・省略 const handleVisibilitychange = useCallback(() => { if (document.visibilityState === ‘hidden’) { if (!ref.current) { return; } ref.current.pause() } }, []); useEffect(() => { window.addEventListener(‘visibilitychange’, handleVisibilitychange, false); return () => { window.removeEventListener(‘visibilitychange’, handleVisibilitychange, false); }; }, [handleVisibilitychange]); ・・・省略
コンテンツが隠れたり、PCのウィンドウがスリープ等によりユーザーから隠れた時に呼ばれるvisibilitychange
イベントのリスナーを設定します。
コールバック関数の実装としてはvisibilityState
がhidden
であれば動画を位置停止するという簡単な処理です。
これに対してコンテンツが隠れた時にpause
関数が呼ばれていることをテストしたいとします。
その時は以下のようにかきます。
test(‘動画再生中に画面が非表示となった場合は一時停止すること’, async () => { const mockPause = jest.spyOn(window.HTMLMediaElement.prototype, ‘pause’).mockImplementation(() => {}); Reflect.defineProperty(document, ‘visibilityState’, { value: ‘hidden’, writable: true, }); await setup(); // 省略していますがテスト対象のページをレンダリングしてます。 act(() => { window.dispatchEvent(new Event(‘visibilitychange’)); }); expect(mockPause).toHaveBeenCalled(); });
まずpause
関数をモック化します。
const mockPause = jest.spyOn(window.HTMLMediaElement.prototype, ‘pause’).mockImplementation(() => {});
その次にdocument
オブジェクトにvisibilityState
プロパティを追加します
jest上でのJS実行はブラウザで実行しているわけではないのでwindow
オブジェクトやdocument
オブジェクトには画面に関する情報は含まれません。
そのため、テストコードの中であらかじめモックとして仕込んで上げる必要があります。
Reflect.defineProperty(document, ‘visibilityState’, { value: ‘hidden’, writable: true, });
次にwindow.dispatchEvent
を使ってイベントをエミュレートします。
ReactTestingLibraryにはfireEvent
というユーザー操作をエミュレートする関数を持っているオブジェクトがあるのですが、visibilitychange
を発生させる関数を持っていなかったのでwindow.dispatchEvent
を使用してます。
ここでactでイベント発生処理をラップしてあげることで、イベント発生が完了して更新処理等が完了してから検証するようにします。
act
でラップしないとイベント発生直後間髪入れずに検証が行われてしまうことでmockPause
の情報が更新される前にexpect
が実行されるのでテストに失敗してしまいます。
なのでこのように何かしらの処理を行って検証対象のデータが反映されてから検証したい場合はactで囲みます。
act(() => { window.dispatchEvent(new Event(‘visibilitychange’)); }); expect(mockPause).toHaveBeenCalled();
このようにテストすることでイベントリスナーのコールバック関数のテストを行うことが可能になります。