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

Jest测试疑问:为何组件内handleSubmit未被检测到调用?

解决Formik组件Jest测试中handleSubmit断言失败的问题

问题场景

  • 参考Testing Library的Formik示例实现了MyForm组件,组件内部定义了异步handleSubmit函数,表单提交时会打印提交值
  • 测试代码中创建了jest.fn()的handleSubmit,但未与组件关联,导致断言该函数被调用1次失败,尽管控制台已正常输出{ firstName: 'John' }

问题根源

测试里的mock函数没有替换组件内部的handleSubmit逻辑,组件依然调用自身定义的提交函数,所以测试中的mock永远不会被触发,断言自然失败。

解决方案

方案1:修改组件,支持传入外部handleSubmit

让组件接受可选的handleSubmit props,优先使用外部传入的函数,否则用内部默认实现:

import { Formik, Form, Field } from 'formik';

const MyForm = ({ handleSubmit: externalSubmit }) => {
  const internalSubmit = async (values) => {
    console.log(values);
  };

  // 优先使用外部传入的提交函数
  const submitHandler = externalSubmit || internalSubmit;

  return (
    <Formik initialValues={{ firstName: '' }} onSubmit={submitHandler}>
      <Form>
        <Field name="firstName" placeholder="请输入名字" />
        <button type="submit">提交</button>
      </Form>
    </Formik>
  );
};

export default MyForm;

对应的测试代码:

import { render, screen, fireEvent } from '@testing-library/react';
import MyForm from './MyForm';

test('表单提交时触发handleSubmit', async () => {
  const mockSubmit = jest.fn();
  // 把mock函数传入组件
  render(<MyForm handleSubmit={mockSubmit} />);

  // 输入表单值
  fireEvent.change(screen.getByPlaceholderText('请输入名字'), { target: { value: 'John' } });
  // 点击提交按钮
  fireEvent.click(screen.getByText('提交'));

  // 断言mock函数被调用1次,且参数正确
  expect(mockSubmit).toHaveBeenCalledTimes(1);
  expect(mockSubmit).toHaveBeenCalledWith({ firstName: 'John' });
});

方案2:不修改组件,用Jest mock替换内部函数

如果无法修改组件代码,可以通过jest.mock直接mock组件内部的提交逻辑:

import { render, screen, fireEvent } from '@testing-library/react';
import MyForm from './MyForm';

// Mock组件,替换内部的handleSubmit
jest.mock('./MyForm', () => {
  const OriginalMyForm = jest.requireActual('./MyForm').default;
  return {
    default: ({ handleSubmit }) => {
      return <OriginalMyForm handleSubmit={handleSubmit} />;
    }
  };
});

test('表单提交时触发handleSubmit', async () => {
  const mockSubmit = jest.fn();
  render(<MyForm handleSubmit={mockSubmit} />);

  fireEvent.change(screen.getByRole('textbox'), { target: { value: 'John' } });
  fireEvent.click(screen.getByText('提交'));

  expect(mockSubmit).toHaveBeenCalledTimes(1);
  expect(mockSubmit).toHaveBeenCalledWith({ firstName: 'John' });
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 08:24:17