React Hooksに対するテストを書いていきたい
ご無沙汰しております。会社のプロダクトチームの新しいメンバーの方がGoのLT会に出ておられて、自分もそういった個人での活動をしたくなった次第です。 React Hooksとは 以下の公式ドキュメントが詳しいです。 https://ja.reactjs.org/docs/hooks-intro.html 前職ではAngularで開発を行なっていたのですが、コンポーネントを定義するためにクラスを定義していて、意図しないタイミングでインスタンス変数が書き換わっているみたいなことがザラにありました。 Hookがない時代のReactも触ったことがあったのですが、同じようにクラスを定義してごにょごにょしなければいけないイメージがあって、現職でReactを触り始めるまではAngularもReactもさして変わらんでしょ、と思っていました。 結論、ReactのHookによりReactがとても気に入りました。関数でコンポーネントを定義できるので理解しやすく挙動も予想しやすいですし、カスタムHookを定義することでコンポーネントのロジックの部分だけを簡単に再利用することができます。 なぜHookに対してテストを書くの? Hookはコンポーネントのロジックを司る部分であるため、テストが書きやすく実行も早いからです。 Hookだけでなく、コンポーネントに対してももちろんテストを書くことができます。以下のレシピ集においても、DOMどんな要素が描画されているのかをテストする方法が示されています。 https://ja.reactjs.org/docs/testing-recipes.html しかし、DOMに対するテストは書きにくいです。評価する部分を書く際にcontainer.querySelector("strong").textContent みたいな感じで要素にアクセスする必要があるのですが、DOM構造を知っていないと書けません。要素があるかないかではなくDOM構造をテストしたいのであれば、テストを書くのではなくStorybookなんかを使って見た目を確認する方が本質的です。 また、DOMに対するテストは実行に時間がかかります。DOMの描画自体に時間がかかるというのもありますし、依存しているコンポーネントもビルドしなければならないという原因もあります。 前職ではDOMに対するテストがビルド時間短縮のボトルネックになっていて、JasmineからJestに移行することでいくらか速くならないかみたいなことを試行錯誤していました。 そこで、Hookに対してテストを書くわけです。HookにはDOM構造の概念がなく、stateに対して評価が書けます。DOMを描画する処理もなく、他のHookに依存しているみたいなことも少ないです。 どうやって書くの? 以下のドキュメントにある書き方を拝借させていただきます。 https://react-hooks-testing-library.com/usage/basic-hooks こんな感じのカスタムHookがあれば、 import { useState, useCallback } from 'react' export default function useCounter(initialValue = 0) { const [count, setCount] = useState(initialValue) const increment = useCallback(() => setCount((x) => x + 1), []) return { count, increment } } こんな感じでテストがかけます。 import { renderHook, act } from '@testing-library/react-hooks' import useCounter from './useCounter' test('should increment counter from custom initial value', () => { const { result } = renderHook(() => useCounter(9000)) act(() => { result.current.increment() }) expect(result.current.count).toBe(9001) }) よくないですか?? 評価対象がHookの返り値としてreturnされるので、result.current.count みたいにさくっとアクセスできちゃいます。Hook内で作ったCallbackを呼び出したい時も、結局Hookの返り値としてreturnされるので、result.current.increment() みたいにさくっと呼び出せちゃいます。 ...