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
相关产品推荐
相关产品推荐

