react-router-dom を使用しているアプリをどうテストするのか
React のテストを初めて間もない初心者です。
以下のような構成で自動テストを書きたいという時にどうしたら良いかまとめました。
-
react-router-dom
を使用 -
Jest
を使用 -
RTL(react-testing-library)
を使用
知っている方からしたら当然かもしれませんが、すぐに見つからなくて結構困ったので備忘録として残しておきます😅
もっと良い案がございましたら教えて頂けると非常に喜びます🙌
結論
公式ドキュメントに書いてありました。
ここに書いてあることが全てです。。。
もう少し詳しく
単純に <Link>
コンポーネントで囲ってあるリンクに対してクリックイベントを発火させても、 location.pathname
は変わりますが、DOM は書き換えられません。
それに、方法によっては describe
ブロックも分けているような完全に別のテスト間で path がリセットされずに他テストに影響を与えることもあるようです。
なので URL を安全に変更し、 path に応じて DOM 要素の書き換えもされる方法を選ぶ必要があります。
history API
を利用すると良いでしょう。
history
を更新する方法はいくつかありますが、個人的に分かりやすいなと思ったのは、 useLocation()
フックを利用して location インスタンスを作成 → <Router>
コンポーネントに作成した location を props として渡す方法です。
import { createMemoryHistory } from 'history'
const history = createMemoryHistory();
history.push("/customers/1")
console.log(history);
ここで出力されるログは、
{
length: 2,
action: 'PUSH',
location: {
pathname: '/customers/1',
search: '',
hash: '',
state: undefined,
key: 'y2y3q3'
},
index: 1,
entries: [
{
pathname: '/',
search: '',
hash: '',
state: undefined,
key: 'xphp2f'
},
{
pathname: '/customers/1',
search: '',
hash: '',
state: undefined,
key: 'y2y3q3'
}
]
// 省略
となります。
テスト対象の DOM が render されるパスを location に明示的に設定しています。
最後に、
render(
<Router history={history}>
<App />
</Router>
)
RTL の render メソッドを使えば完了です。あとは好きにアサーションを書いていきましょう。
注意としては、 render されるコンポーネント側で useHistory
などで history を参照している場合には作成した history の情報がそのまま渡りますが、 useParams
などには反応しません。
当然と言えば当然ですが、ここはモックにするとかしないといけないのでしょうかね🧐
React(JS)のテスト難しい。。。
Discussion