なぜこの記事を書いたか
reactに関するテストの勉強をしていて、useSelector
のモックの仕方で詰まりました。この経験からこの記事を残そうを思います。
useSelectorのモックの仕方はいくつか記事があるとは思うのですが、具体的に今回詰まったのは、一つのコンポーネント(or カスタムフック)で複数回useSelectorを呼び出す場合でした。この記事では、そんな複数回のuseSelectorの呼び出しにも対応させています。
ケース
早速ですが、複数回のuseSelectorの呼び出しとは何かというと、以下のようなケースです。
const useMyCloset = () => {
const isThinkingTops = useSelector(state => state.tops.isThinking);
const tShirts = useSelector(state => state.tops.tShirts);
const loadMyTshirts = () => {
if (isThinking) return null;
return tShirts;
}
return {
loadMyTshirts
}
}
useSelectorによって値を取得する際は、一度のuseSelectorで、objectを取得して、その値を使用するのではなく、何度もuseSelectorを呼び出して一番小さい単位で取得することが推奨されています。(参考)
よって、先述のコードは以下のように書くと、あまりよろしくないということになります。(なぜこのようにした方が良いかは、本記事では省きます。)
const useMyCloset = () => {
// ↓ 一度のuseSelector呼び出しで値を取得している
const tops = useSelector(state => state.tops);
const loadMyTshirts = () => {
if (tops.isThinkingTops) return null
return tops.tShirts
}
return {
loadMyTshirts
}
}
じゃあどうするのか
さて、少し話題が逸れましたが、複数回のuseSelector呼び出しは、以下のように、mockImplementation
を使った方法でモックできます。
useSelectorは、引数にrootStateを取るselector関数を受け取り、それを実行するだけです。
よって, useSelectorの振る舞いをモックした上で、selector関数でエラーが出ないように、dummyのRootStateをselector関数の引数に渡すようにします。
// 他import
import {useSelector} from 'react-redux';
jest.mock('react-redux');
const useSelectorMock = useSelector as jest.Mock;
const dummyStore = {
tops: {
isThinking: false,
tShirts: ['tShirtsA', 'tShirtsB', 'tShirtsC']
}
}
beforeEach(() => {
useSelectorMock.mockImplementation(selector => selector(dummyStore))
});
afterEach(() => {
jest.resetAllMocks();
});
describe('useMyCloset', () => {
it('testA', () => {
// some test
});
});
他にも何かもっといい方法があれば教えてくださいませ〜〜!!