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

React Testing Library测试问题:输入框值无法更新

问题:Formik包裹Office UI Fabric TextField的自定义组件测试时输入值不更新

我正在开发一个自定义React组件,该组件在Formik表单中包裹了Office UI Fabric TextField。尽管遵循了React和Formik处理输入框的常规模式,但使用React Testing Library测试组件时遇到问题:在Jest中模拟change事件后,输入框的值并未更新。

组件代码

const FMIconButtonTextField: React.FC<Props> = props => {
  const { label, styles, name, callOutSpanText } = props;
  const [isCalloutVisible, setIsCalloutVisible] = useState(false);
  const inputId = getId(name);
  const [field, { touched, error }] = useField(name);

  return (
    <>
      <TextField
        {...field}
        {...props}
        label={label}
        errorMessage={touched && error ? error : null}
        id={inputId}
      />
    </>
  );
};

测试代码

it('allows input into the voucher code field', async () => {
  const initialValues = { voucherCode: '' };
  const { container, findByDisplayValue } = render(
    <Formik initialValues={initialValues} onSubmit={jest.fn()}>
      <Form>
        <FMIconButtonTextField
          name="voucherCode"
          label="Voucher Code *"
          callOutSpanText="Voucher Code must contain at least 5 characters and no more than 20 characters, and is allowed A to Z, 0 to 9, and _."
          placeholder="Only A-Z or 0-9 or _"
        />
      </Form>
    </Formik>
  );

  const input = container.querySelector('input[name="voucherCode"]');
  fireEvent.change(input, { target: { value: 'ABC123' } });

  // Wait for React's state update to propagate
  await findByDisplayValue('ABC123'); // This ensures the input has received and displays the new value

  expect(input.value).toBe('ABC123');
});

错误结果

expect(received).toBe(expected) // Object.is equality

Expected: "ABC123"
Received: ""

解决方案

1. 修复组件的props覆盖问题

你当前组件里{...props}放在{...field}之后,会导致props中的name、onChange等属性直接覆盖Formikfield对象提供的核心属性,让Formik的状态更新逻辑完全失效。调整展开顺序,先放{...props}再放{...field}:

return (
  <>
    <TextField
      {...props}
      {...field}
      label={label}
      errorMessage={touched && error ? error : null}
      id={inputId}
    />
  </>
);

这样Formik的onChange、value等状态同步属性会优先生效,保证输入内容能同步到Formik的状态中。

2. 优化测试写法

  • 别用container.querySelector,改用React Testing Library推荐的getByLabelText或getByRole,更贴合测试最佳实践:
const input = screen.getByLabelText(/Voucher Code \*/);
  • 不需要额外用findByDisplayValue等待,fireEvent.change会同步触发状态更新,直接断言即可;只有异步更新场景才需要等待方法。

调整后的测试代码:

import { screen } from '@testing-library/react';

it('allows input into the voucher code field', () => {
  const initialValues = { voucherCode: '' };
  render(
    <Formik initialValues={initialValues} onSubmit={jest.fn()}>
      <Form>
        <FMIconButtonTextField
          name="voucherCode"
          label="Voucher Code *"
          callOutSpanText="Voucher Code must contain at least 5 characters and no more than 20 characters, and is allowed A to Z, 0 to 9, and _."
          placeholder="Only A-Z or 0-9 or _"
        />
      </Form>
    </Formik>
  );

  const input = screen.getByLabelText(/Voucher Code \*/);
  fireEvent.change(input, { target: { value: 'ABC123' } });

  expect(input.value).toBe('ABC123');
});

3. 验证Office UI Fabric TextField的绑定

Office UI Fabric的TextField会将内部输入框的值与value属性绑定,调整props顺序后,Formik的field.value会覆盖props中可能存在的默认值,确保状态能正确同步到输入框。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 07:35:59