React18 にて testing-library/react のrenderHook の wrapper へ Props を更新してテストがしたいんじゃ

React18になり、今まで使っていた testing-library/react-hooks が使えなくなったことはもう周知の事実。しかし、renderHook に wrapper を渡してprops を変更してテストしていた項目を testing-library/react の renderHook で代用するのがむずかったのでここに残す。

/**
 * hook関数を実行し、返された値を検証するための必要な環境を提供するReactコンポーネントを定義し、
 * それをラップして renderHook関数を呼び出します
 *
 * @param hook // テスト対象のReact Hooksの関数
 * @param provider // hook 関数で使用されるReactコンポーネントのプロバイダーとして使用されるコンポーネント
 * @param options // テストのオプション、およびラッパーコンポーネントのプロパティ
 *
 * NOTICE: テストコードで使用するので @ts-ignore を許容しています。使わない方法があったらそちらを使っていきたいところ
 */
export const customRenderHook = <
	Props,
	Q extends Queries,
	Container extends Element | DocumentFragment,
	BaseElement extends Element | DocumentFragment,
	Result,
>(
	hook: (props?: Props) => Result,
	provider: React.ComponentType<Props>,
	options?: Omit<RenderHookOptions<Props, Q, Container, BaseElement>, 'wrapper'> & {
		wrapperProps?: Props & { value: IStoreContext };
	},
): RenderHookResult<Result, Props> => {
	// props引数から wrapperProps を分離し、 provider引数を使用して子要素を含めたReactコンポーネントを生成
	const Wrapper: React.FC<Props & { children: React.ReactNode }> = ({ children, ...rest }) => {
		const WrapperComponent = provider as React.ComponentType<Omit<Props, 'children'>>;
		// eslint-disable-next-line @typescript-eslint/ban-ts-comment
		// @ts-ignore
		return <WrapperComponent {...rest}>{children}</WrapperComponent>;
	};
	// wrapperプロパティを含む renderHook関数を返す
	return renderHook(hook, {
		...options,
		// eslint-disable-next-line @typescript-eslint/ban-ts-comment
		// @ts-ignore
		wrapper: props => <Wrapper {...options?.wrapperProps} {...props} />,
	});
};

この記事が気に入ったらサポートをしてみませんか?