You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用React Testing Library测试useFormik Hook表单时无法触发onSubmit的问题求助

问题根源分析

你遇到的核心问题是测试用例里的mockSubmit完全没和组件内部的Formik onSubmit逻辑关联起来。你的WithMaterialUI组件里硬编码了自己的onSubmit函数(弹出alert),而测试里定义的mockSubmit从未被组件调用,所以自然不会触发预期的断言。

解决方案

这里提供两种可行的解决思路,你可以根据自己的需求选择:

方案1:将onSubmit作为组件Props传入(推荐,更符合可测试性设计)

把组件改成接受外部传入的onSubmit,这样测试时就能轻松注入mock函数:

修改组件代码

export const WithMaterialUI = ({ onSubmit }) => {
  const formik = useFormik({
    initialValues: { email: "foobar@example.com" },
    validationSchema: validationSchema,
    onSubmit: (values) => {
      // 保留原有业务逻辑(如果需要)
      alert(JSON.stringify(values, null, 2));
      // 调用外部传入的回调,方便测试
      onSubmit(values);
    }
  });
  
  // 其余代码保持不变
  return (
    <div>
      <form onSubmit={formik.handleSubmit} data-testid="form">
        <TextField
          data-testid="email"
          fullWidth
          id="email"
          name="email"
          label="Email"
          value={formik.values.email}
          onChange={formik.handleChange}
          error={formik.touched.email && Boolean(formik.errors.email)}
          helperText={formik.touched.email && formik.errors.email}
        />
        <Button color="primary" variant="contained" fullWidth type="submit">
          Submit
        </Button>
      </form>
    </div>
  );
};

如果不需要原有alert逻辑,也可以直接复用props的onSubmit:

export const WithMaterialUI = ({ onSubmit }) => {
  const formik = useFormik({
    initialValues: { email: "foobar@example.com" },
    validationSchema: validationSchema,
    onSubmit
  });
  // 其余代码不变
};

修改测试用例

const mockSubmit = jest.fn();
describe("Test for formik onSubmit", () => {
  it("should handle form submission", async () => {
    const { getByTestId } = render(<WithMaterialUI onSubmit={mockSubmit} />);
    const email = getByTestId("email");
    const form = getByTestId("form");
    
    fireEvent.change(email, { target: { value: "abc@gmail.com" } });
    fireEvent.submit(form);
    
    await waitFor(() => {
      // 不仅验证被调用,还可以校验传入的参数是否正确
      expect(mockSubmit).toHaveBeenCalledWith({ email: "abc@gmail.com" });
    });
  });
});

方案2:直接测试组件原有行为(无需修改组件结构)

如果你不想调整组件设计,也可以直接测试组件的原生行为(比如alert是否被触发):

describe("Test for formik onSubmit", () => {
  it("should trigger alert with correct values on submission", async () => {
    // 模拟window.alert方法
    window.alert = jest.fn();
    
    const { getByTestId } = render(<WithMaterialUI />);
    const form = getByTestId("form");
    
    fireEvent.submit(form);
    
    await waitFor(() => {
      expect(window.alert).toHaveBeenCalledWith(
        JSON.stringify({ email: "foobar@example.com" }, null, 2)
      );
    });
    
    // 测试完成后恢复原方法,避免影响其他测试
    window.alert.mockRestore();
  });
});

额外小提示

测试里的act()包裹其实可以省略——fireEvent和render已经自动处理了React的更新流程,waitFor也会正确处理异步逻辑。

内容的提问来源于stack exchange,提问作者krsna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.01 02:22:30