React Testing Library中禁用输入框仍可赋值的测试问题
为什么禁用的输入框在使用fireEvent.input时仍会被赋值?
我用React、Vitest和Testing Library写了如下测试代码:
import { describe, expect, it } from 'vitest'; import { fireEvent, render, screen } from '@testing-library/react'; describe('App button Problem', () => { it('types in the input correctly', async () => { render(<input type={'text'} disabled={false}/> ); const input : HTMLInputElement = screen.getByRole('textbox'); fireEvent.input(input, { target: { value: 'test' } }); expect( input.value).toBe('test'); // 此断言正常通过 }); it('does not types in the input if disabled', async () => { render(<input type={'text'} disabled={true}/> ); const input : HTMLInputElement = screen.getByRole('textbox'); fireEvent.input(input, { target: { value: 'test' } }); expect( input.value).toBe(''); // 此断言失败 }); });
运行测试后得到错误:
AssertionError: expected 'test' to be '' // Object.is equality Expected : Actual :test
问题原因
fireEvent是直接模拟DOM事件触发的工具,它不会像真实用户交互那样遵守输入框的disabled状态限制。在真实浏览器中,禁用的输入框不会响应输入事件,也不会更新值,但fireEvent会强制触发input事件并直接设置元素的value属性,所以即便输入框处于禁用状态,值还是会被修改。
解决方案
方案1:使用user-event模拟真实用户行为
推荐使用@testing-library/user-event,它的交互逻辑完全贴近真实用户,会自动尊重元素的disabled状态:
- 安装依赖:
npm install --save-dev @testing-library/user-event
- 修改测试代码:
import { describe, expect, it } from 'vitest'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; describe('App button Problem', () => { const user = userEvent.setup(); it('types in the input correctly', async () => { render(<input type={'text'} disabled={false}/> ); const input : HTMLInputElement = screen.getByRole('textbox'); await user.type(input, 'test'); expect(input.value).toBe('test'); }); it('does not type in the input if disabled', async () => { render(<input type={'text'} disabled={true}/> ); const input : HTMLInputElement = screen.getByRole('textbox'); await user.type(input, 'test'); expect(input.value).toBe(''); }); });
方案2:调整断言逻辑(无需额外依赖)
如果不想引入新依赖,可以直接断言输入框的禁用状态,而不是依赖值的变化:
it('input should be disabled', async () => { render(<input type={'text'} disabled={true}/> ); const input : HTMLInputElement = screen.getByRole('textbox'); expect(input).toBeDisabled(); });
内容的提问来源于stack exchange,提问作者Chen Peleg
相关产品推荐
相关产品推荐

