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

使用Jest编写单元测试时如何mock Formik的useFormikContext钩子

最优实现方案汇总

这里提供3种可直接落地的方案,你可以根据项目场景选择:


方案1:用类型断言跳过不必要的属性校验(最快实现)

你的组件仅用到useFormikContext返回值中的getFieldMeta方法,完全不需要补齐所有20+属性,用TS类型断言绕开类型校验即可,代码量直接缩减90%:

import * as formik from 'formik';
import type { FormikContextType } from 'formik';

describe('AphInputLabel UnitTests', () => {
  const useFormikContextMock = jest.spyOn(formik, 'useFormikContext');
  // 仅mock你实际用到的getFieldMeta方法
  const mockGetFieldMeta = jest.fn((fieldName) => ({
    // 按测试场景返回error值即可,其他getFieldMeta返回属性没用到可以不写
    error: fieldName === 'testName' ? '字段错误提示' : undefined
  }));

  beforeEach(() => {
    useFormikContextMock.mockReturnValue({
      getFieldMeta: mockGetFieldMeta
      // 其余所有没用到的属性直接用类型断言跳过校验
    } as unknown as FormikContextType<any>);
  });

  // 后续测试用例正常编写即可
});

优缺点:实现最快,适合组件依赖Formik属性少的场景;如果后续组件新增用到其他Formik属性,需要同步更新mock。


方案2:直接用Formik组件包裹被测组件(最推荐)

完全不需要mock钩子,直接模拟组件真实使用场景,用Formik原生组件包裹被测组件,既不需要处理类型问题,测试结果也更贴近线上运行情况,同时Formik内置的Field组件也不需要额外mock:

import { render, screen } from '@testing-library/react';
import { Formik } from 'formik';
import AphControlInput from './AphControlInput';

describe('AphInputLabel UnitTests', () => {
  it('字段报错时正确展示invalid样式', () => {
    render(
      <Formik
        initialValues={{ testName: '' }}
        initialErrors={{ testName: '该字段为必填项' }}
        initialTouched={{ testName: true }}
        onSubmit={() => {}}
      >
        <AphControlInput name="testName" label="测试输入框" />
      </Formik>
    );
    // 直接校验渲染结果即可
    expect(screen.getByLabelText('测试输入框').parentElement).toHaveClass('aph-control-input--invalid');
  });
});

优缺点:不需要维护任何mock逻辑,测试可靠性最高,后续组件新增依赖Formik属性也不用修改测试代码,是优先推荐的方案。


方案3:封装通用mock工厂(适合多组件复用场景)

如果你的项目里有大量组件依赖useFormikContext,可以提前封装一个通用的mock工厂函数,写一次之后所有组件测试都可以复用,每次只需要传需要自定义的属性即可:

// 单独抽离的通用mock工具
import type { FormikContextType } from 'formik';

export function createMockFormikContext(override: Partial<FormikContextType<any>> = {}): FormikContextType<any> {
  return {
    values: {},
    errors: {},
    touched: {},
    isSubmitting: false,
    isValidating: false,
    submitCount: 0,
    getFieldMeta: jest.fn(() => ({ error: undefined, touched: false, value: '' })),
    setStatus: jest.fn(),
    setErrors: jest.fn(),
    setSubmitting: jest.fn(),
    setTouched: jest.fn(),
    setValues: jest.fn(),
    setFieldValue: jest.fn(),
    setFieldError: jest.fn(),
    setFieldTouched: jest.fn(),
    resetForm: jest.fn(),
    validateField: jest.fn(),
    setFormikState: jest.fn(),
    validateForm: jest.fn(() => Promise.resolve({})),
    submitForm: jest.fn(() => Promise.resolve()),
    handleSubmit: jest.fn(),
    handleReset: jest.fn(),
    ...override,
  } as FormikContextType<any>;
}

// 测试用例中使用
useFormikContextMock.mockReturnValue(createMockFormikContext({
  getFieldMeta: jest.fn((name) => ({ error: '自定义错误提示' }))
}));

优缺点:一次封装全项目复用,适合需要单独测试组件、不想引入Formik组件渲染的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 22:15:03