React Hook Form表单测试报错:jest.fn()调用次数不匹配
问题排查与解决方案
核心问题分析
你的测试失败主要由以下几个关键问题导致:
1. 组件内部覆盖了传入的onSubmit回调
在ContactForm组件中,你接收了props.onSubmit,但紧接着又声明了同名的内部变量onSubmit,直接覆盖了外部传入的jest mock函数,导致测试中的onSubmit永远不会被调用:
// 组件中错误的写法 export function ContactForm({ onSubmit }: ContactFormProps) { // ... // 这里的onSubmit覆盖了props传入的回调 const onSubmit: SubmitHandler<FormSchemaType> = data => { ... }; }
2. fireEvent.input调用方式错误
你直接传入字符串作为第二个参数,正确的写法应该是传递包含target.value的对象:
// 错误写法 fireEvent.input(emailInput, "abc@abc.com"); // 正确写法 fireEvent.input(emailInput, { target: { value: "abc@abc.com" } });
3. 可能存在表单校验未通过的情况
由于使用了zodResolver,如果测试输入不符合FormSchema的校验规则,handleSubmit会直接阻断提交流程,不会触发回调。
4. 测试中多余的FormProvider包装
ContactForm内部已经创建了自己的useForm实例并通过FormProvider提供上下文,测试外层额外包装的FormProvider会造成上下文冲突(虽然不是核心问题,但应该移除)。
修复步骤
第一步:修正组件的onSubmit逻辑
将内部处理函数改名,确保调用外部传入的回调:
export function ContactForm({ onSubmit: submitCallback }: ContactFormProps) { const methods = useForm<FormSchemaType>({ resolver: zodResolver(FormSchema), }); const { handleSubmit, reset } = methods; // 内部处理逻辑后调用外部传入的回调 const handleFormSubmit: SubmitHandler<FormSchemaType> = (data) => { // ...你的业务逻辑 submitCallback(data); // 触发外部传入的onSubmit }; return ( <> <FormProvider {...methods}> <FormWrapper> <form onSubmit={handleSubmit(handleFormSubmit)}> .... </form> </FormWrapper> </FormProvider> </> ); }
第二步:修正测试代码
describe("Form", () => { const onSubmit = jest.fn(); const renderForm = () => { customRender( <ContactForm onSubmit={onSubmit} />, { withRouter: true } ); }; it("successful submit", async () => { renderForm(); const emailInput = screen.getByRole("textbox", { name: /email/i }); const fNameInput = screen.getByRole("textbox", { name: /fname/i }); const submitButton = screen.getByRole("button", { name: /submit/i }); // 正确设置输入值 fireEvent.input(emailInput, { target: { value: "abc@abc.com" } }); fireEvent.input(fNameInput, { target: { value: "Alex" } }); // 触发提交 fireEvent.click(submitButton); // 如果组件的submit是异步操作,必须用waitFor等待回调执行 await waitFor(() => { expect(onSubmit).toHaveBeenCalledTimes(1); }); }); });
额外注意事项
- 校验
FormSchema规则:确保测试输入符合校验要求(比如邮箱格式正确、姓名不为空等),可以通过查询页面上的错误提示元素排查:screen.queryByText(/请输入有效的邮箱/i)。 - 异步处理:如果
handleFormSubmit包含异步操作(比如接口请求),必须使用waitFor或async/await等待异步流程完成后再断言。
内容的提问来源于stack exchange,提问作者ReactDeveloper
相关产品推荐
相关产品推荐

