聞きたいこと
Nextjs + Recoil でWebアプリを作成しています。
独自で作成したカスタムフックををJestでテストしようと思っているのですが、そのカスタムフック内でuseRouterを使用しているため、下のエラーが発生してしまいます。
unit test for custom hook useIds TypeError: Cannot read property 'query' of null 17 | const [ids, setIds] = useRecoilState(idsState); 18 | const router = useRouter(); > 19 | const { type } = router.query;
実際に実行したテストコードはこちらです。
import * as React from 'react'; import { act, renderRecoilHook } from 'react-recoil-hooks-testing-library'; import { useIds } from '@/hooks'; import { withMockedRouter, MockedRouter } from '@/utils/mock'; it('custom hook test', () => { const { result } = renderRecoilHook(() => useIds()); act(() => { console.log(result.current.ids); }) })
またテスト対象のカスタムフックはこちらです。
import * as React from 'react'; import { useRouter } from 'next/router'; import { atom, useRecoilState } from 'recoil'; import { fetchIdsByType } from '@/repositories'; const initialState: { [type: string]: number[]; } = {}; export const idsState = atom({ key: 'idsState', default: initialState, }); const useIds = () => { const [ids, setIds] = useRecoilState(idsState); const router = useRouter(); const { type } = router.query; React.useEffect(() => { if (router.asPath !== router.route) { // @ts-ignore fetchIdsByType(type).then((ids: number[]) => { setIds((prevState) => { return { ...prevState, // @ts-ignore [type]: ids, }; }); }); } }, [router]); // @ts-ignore return ids[type]; }; export { useIds };
試してみたこと
上のテストコード内で実行されている renderRecoilHook
の第2引数に、NextjsのRoutingに関するコンポーネントをWrapperとして渡せば良さそうだと思い、下のような実装を試してみました。
import * as React from 'react'; import { act, renderRecoilHook } from 'react-recoil-hooks-testing-library'; import { useIds } from '@/hooks'; import { withMockedRouter, MockedRouter } from '@/utils/mock'; it('custom hook test', () => { const wrapper = (children) => <MockedRouter>{children}</MockedRouter>; const { result } = renderRecoilHook(() => useIds(), { wrapper }); act(() => { console.log(result.current.ids); }) const { result } = renderHook(() => useCount()); act(() => { result.current.increment(); }); })
- MockRouter
import React from "react"; import { NextRouter } from 'next/router'; import { RouterContext } from 'next/dist/next-server/lib/router-context'; export const MockedRouter = (router: Partial<NextRouter> = {}, children: React.ReactElement) => { const mockedRouter = { route: '', pathname: '', query: {}, asPath: '', push: async () => true, replace: async () => true, reload: () => null, back: () => null, prefetch: async () => undefined, beforePopState: () => null, events: { on: () => null, off: () => null, emit: () => null, }, }; // @ts-ignore return <RouterContext.Provider value={mockedRouter}>{ children }</RouterContext.Provider>; };
試してみた結果、下のようなエラーが表示されてしまいました。
custom hook test Objects are not valid as a React child (found: object with keys {}). If you meant to render a collection of children, use an array instead. 8 | it('custom hook test', () => { 9 | const wrapper = (children) => <MockedRouter>{children}</MockedRouter>; > 10 | const { result } = renderRecoilHook(() => useIds(), { wrapper });
ここまで試してみましたが、自力解決が難しかったので、どなたか解決の糸口を教えてほしいです。
あなたの回答
tips
プレビュー