受控Input组件Jest测试失败原因及有效测试方案咨询
自定义Input组件受控模式下单元测试失败原因及有效测试方案
测试失败的核心原因
你第二个测试用例失败的本质是:当给<Input />传入value=""时,组件进入受控模式——它的输入值完全由外部传入的value props决定。
在你的测试代码里,虽然用user.type()模拟了输入操作,也传入了onChangeMock,但这个mock函数只是空实现,并没有更新组件的value props。组件接收到的value始终是初始的空字符串,所以input元素的值不会发生变化,最后expect(input).toHaveValue('new input value')自然会断言失败。
而第一个测试没有传入value props,组件处于非受控模式,input元素会自行维护内部状态,因此输入后值能正常更新,测试顺利通过。
受控组件的有效测试用例
针对受控组件,需要模拟真实业务中的使用场景(通常配合父组件的状态管理),编写以下几类测试来覆盖核心逻辑:
1. 初始值渲染验证
验证组件能正确渲染传入的初始value:
it('should render initial value correctly', () => { const { getByRole } = render(<Input value="initial content" />); const input = getByRole('textbox'); expect(input).toHaveValue('initial content'); });
2. 输入触发onChange并同步更新值
在测试中用状态管理模拟父组件的行为,确保输入后value能正确同步:
it('should update value when typing in controlled mode', async () => { const user = userEvent.setup(); const [value, setValue] = useState(''); const { getByRole } = render( <Input value={value} onChange={setValue} /> ); const input = getByRole('textbox'); await user.type(input, 'test input'); expect(input).toHaveValue('test input'); expect(value).toBe('test input'); });
3. 禁用状态测试
验证组件在disabled为true时,无法输入且不会触发onChange:
it('should block input and onChange when disabled', async () => { const user = userEvent.setup(); const onChangeMock = jest.fn(); const { getByRole } = render( <Input value="locked" disabled onChange={onChangeMock} /> ); const input = getByRole('textbox'); await user.type(input, 'try edit'); expect(input).toHaveValue('locked'); expect(onChangeMock).not.toHaveBeenCalled(); });
4. onChange回调参数验证
确保onChange能正确传递输入的内容:
it('should call onChange with correct input value', async () => { const user = userEvent.setup(); const onChangeMock = jest.fn(); const { getByRole } = render( <Input value="" onChange={onChangeMock} /> ); const input = getByRole('textbox'); await user.type(input, 'hello world'); expect(onChangeMock).toHaveBeenCalledTimes(11); // 每个字符触发一次回调 expect(onChangeMock).toHaveBeenLastCalledWith('hello world'); });
5. 非受控模式行为验证(可选)
补充非受控模式的测试,覆盖组件的完整使用场景:
it('should work correctly in uncontrolled mode', async () => { const user = userEvent.setup(); const onChangeMock = jest.fn(); const { getByRole } = render(<Input onChange={onChangeMock} />); const input = getByRole('textbox'); await user.type(input, 'uncontrolled content'); expect(input).toHaveValue('uncontrolled content'); expect(onChangeMock).toHaveBeenLastCalledWith('uncontrolled content'); });
内容的提问来源于stack exchange,提问作者Manuel Bosi
相关产品推荐
相关产品推荐

