如何为接收Formik状态作为props的组件编写测试?
问题解决:React Testing Library测试ComponentB时的钩子调用错误
错误原因
测试代码里直接在test函数(普通JavaScript函数)中调用useFormik钩子,违反了React钩子的调用规则——钩子只能在React函数组件的顶层或自定义钩子内部调用,因此触发Invalid hook call错误。
解决方案
ComponentB仅依赖传入的formikBag props,不需要在测试中真实调用useFormik,直接构造符合结构的模拟对象即可,有两种常用方式:
方案一:手动构造Mock的formikBag
直接模拟ComponentB用到的属性,简单高效,适合仅测试渲染逻辑的场景:
// ComponentB测试代码修改后 test('should render ComponentB', async () => { // 构造mock的formikBag,包含组件用到的属性 const mockFormikBag = { values: { name: "xxx", id: 1 }, setFieldValue: jest.fn(), // 如果组件用到该方法,用jest.fn()模拟 setValues: jest.fn() }; const { asFragment } = render( <ThemeProvider> <MockedProvider mocks={[mockQueryMe]}> <ComponentB formikBag={mockFormikBag} /> </MockedProvider> </ThemeProvider> ); await waitFor(() => { expect(asFragment()).toMatchSnapshot(); }); });
方案二:用临时组件包裹调用useFormik
如果需要更贴近真实场景(比如验证formik的状态变化对ComponentB的影响),可以在测试中定义一个临时的React函数组件,在内部调用useFormik后传递给ComponentB:
// ComponentB测试代码修改后 test('should render ComponentB with real formik context', async () => { // 定义临时组件,内部调用useFormik const TestWrapper = () => { const formikBag = useFormik({ initialValues: { name: "xxx", id: 1 }, }); return <ComponentB formikBag={formikBag} />; }; const { asFragment } = render( <ThemeProvider> <MockedProvider mocks={[mockQueryMe]}> <TestWrapper /> </MockedProvider> </ThemeProvider> ); await waitFor(() => { expect(asFragment()).toMatchSnapshot(); }); });
说明
- 方案一适合快速验证组件的渲染结果,无需依赖Formik的真实逻辑;
- 方案二更适合测试组件与Formik状态联动的场景,比如修改值后组件的更新逻辑。
内容的提问来源于stack exchange,提问作者K Pisco
相关产品推荐
相关产品推荐

