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

如何Mock React Hook Form中Controller的render属性以覆盖测试

解决React Hook Form Controller组件render属性测试覆盖问题

问题场景

使用React Testing Library测试自定义组件时,发现React Hook Form中Controller组件的render属性内的代码未被测试覆盖,需要补充测试逻辑覆盖这部分代码。

组件代码(InputComponent)

<div>
  <label>{label}</label>
  <Controller
    control={control}
    name={name}
    rules={validate}
    render={({ field: { onChange, value, name: iName } }) => (
      <select
        name={iName}
        onChange={(e) => {
          onChange(e.target.value);
          action.handleInputValidation(e);
        }}
        onFocus={(e) => action.handleOnfocus(e)}
        value={value}
      >
        <option value="">{placeholder}</option>
        {data.map((option) => (
          <option
            key={`option-${option.value}`}
            value={option.value}
          >
            {option.label}
          </option>
        ))}
      </select>
    )}
  />
</div>

初始测试文件

describe('Component', () => {
  let wrapper;
  beforeEach(() => {
    wrapper = render(
      <InputComponent
        name={name}
        placeholder={placeholder}
        label={label}
        data={dataSchema}
        controller={Controller}
        register={jest.fn()}
      />
    );
  });

  test('InputComponent should be rendered', () => {
     // run expects
  });
});

解决方案

1. 正确配置React Hook Form测试环境

Controller依赖于React Hook Form的control对象,测试时需要通过useForm创建合法的control实例,而非直接传入Controller组件。同时要mock组件依赖的action对象,以便验证回调是否触发。

import { render, screen, fireEvent } from '@testing-library/react';
import { useForm } from 'react-hook-form';
import InputComponent from './InputComponent';

// Mock action对象
const mockAction = {
  handleInputValidation: jest.fn(),
  handleOnfocus: jest.fn()
};

describe('InputComponent', () => {
  let control;
  const testProps = {
    name: 'test-select',
    placeholder: '请选择',
    label: '测试选择器',
    data: [
      { value: '1', label: '选项1' },
      { value: '2', label: '选项2' }
    ],
    action: mockAction // 传入mock的action
  };

  beforeEach(() => {
    // 创建React Hook Form的control实例
    const { control: formControl } = useForm({
      defaultValues: { [testProps.name]: '' }
    });
    control = formControl;

    render(
      <InputComponent
        {...testProps}
        control={control} // 传入合法的control
      />
    );
  });

2. 测试render内的UI渲染

验证render函数生成的select元素、选项是否正确渲染:

test('should render select element with correct options', () => {
  // 验证标签存在
  expect(screen.getByLabelText(testProps.label)).toBeInTheDocument();
  
  // 验证select元素存在
  const selectElement = screen.getByRole('combobox');
  expect(selectElement).toBeInTheDocument();
  
  // 验证默认选项和自定义选项存在
  expect(screen.getByText(testProps.placeholder)).toBeInTheDocument();
  expect(screen.getByText('选项1')).toBeInTheDocument();
  expect(screen.getByText('选项2')).toBeInTheDocument();
});

3. 测试render内的交互逻辑

覆盖onChange、onFocus等回调,验证触发逻辑是否正常:

test('should trigger handleOnfocus when select is focused', () => {
  const selectElement = screen.getByRole('combobox');
  
  fireEvent.focus(selectElement);
  
  // 验证handleOnfocus被调用
  expect(mockAction.handleOnfocus).toHaveBeenCalledTimes(1);
  expect(mockAction.handleOnfocus).toHaveBeenCalledWith(expect.any(Object));
});

test('should trigger onChange and handleInputValidation when selecting an option', () => {
  const selectElement = screen.getByRole('combobox');
  
  // 选择选项1
  fireEvent.change(selectElement, { target: { value: '1' } });
  
  // 验证handleInputValidation被调用
  expect(mockAction.handleInputValidation).toHaveBeenCalledTimes(1);
  expect(mockAction.handleInputValidation).toHaveBeenCalledWith(expect.any(Object));
});

4. (可选)Mock Controller组件(不推荐)

如果需要单独测试render函数逻辑,可mockController组件,让它直接执行传入的render函数:

import { Controller } from 'react-hook-form';

// Mock Controller,直接返回render函数的结果
jest.mock('react-hook-form', () => ({
  ...jest.requireActual('react-hook-form'),
  Controller: ({ render }) => render({
    field: {
      onChange: jest.fn(),
      value: '',
      name: 'test-select'
    }
  })
}));

// 之后的测试可以直接验证render生成的元素和交互

注意:React Testing Library的理念是测试组件的实际行为而非实现细节,因此优先推荐通过测试UI交互来覆盖render内的代码,而非mockController。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 12:40:21