React Testing Library userEvent.upload上传文件至input时出现‘Cannot read property 'toLowerCase' of undefined’错误求助
问题分析
你踩的这个坑其实很典型——@testing-library/user-event的upload方法只认原生DOM元素,但你传进去的是Enzyme封装后的Wrapper对象。当userEvent内部尝试检查元素类型时,它访问了Wrapper上不存在的属性,直接触发了Cannot read property 'toLowerCase' of undefined的报错。
解决方案
1. 从Enzyme Wrapper里抠出原生DOM元素
Enzyme的at(0)返回的还是它自己的Wrapper实例,得用.get(0)方法才能拿到真实的<input> DOM节点:
const inputWrapper = wrapper.find('#contained-button-file').at(0); const inputElement = inputWrapper.get(0); // 这才是userEvent要的原生元素
2. 正确调用userEvent.upload(别套waitFor)
userEvent.upload本身就是异步函数,直接await它就行,没必要嵌套在waitFor里画蛇添足:
await userEvent.upload(inputElement, file);
3. 修正断言逻辑
Enzyme的Wrapper对象根本没有files属性,要断言文件是否上传成功,得从原生DOM元素上取:
expect(inputElement.files.length).toBe(1);
更推荐的做法是直接测试组件的业务逻辑——比如断言你的setPhoto回调函数被正确调用(如果已经mock了它的话),毕竟React组件的核心是通过onChange处理文件,而非直接检查DOM属性:
// 先在props里mock setPhoto const mockSetPhoto = jest.fn(); const wrapper = mount(<AddDefect {...props} setPhoto={mockSetPhoto}/>); // ...上传文件后 expect(mockSetPhoto).toHaveBeenCalled(); // 还能进一步验证传入的文件信息是否正确 const uploadedFile = mockSetPhoto.mock.calls[0][0].target.files[0]; expect(uploadedFile.name).toBe('test.png'); expect(uploadedFile.type).toBe('image/png');
完整修改后的测试代码
it('check the callbacks', async ()=>{ const file = new File(['(⌐□_□)'], 'test.png', { type: 'image/png' }); const mockSetPhoto = jest.fn(); const wrapper = mount(<AddDefect {...props} setPhoto={mockSetPhoto}/>); // 处理描述输入 wrapper.find('#description').at(0).simulate('click'); wrapper.find('#descriptionfield').at(0).find('input').at(0).simulate('change', { target: { value: 'test' } }); // 获取原生input并上传文件 const inputWrapper = wrapper.find('#contained-button-file').at(0); const inputElement = inputWrapper.get(0); await userEvent.upload(inputElement, file); // 验证文件上传状态 expect(inputElement.files.length).toBe(1); expect(mockSetPhoto).toHaveBeenCalled(); // 测试发送和返回按钮 wrapper.find('#send').at(0).simulate('click'); expect(onSendData).toHaveBeenCalled(); wrapper.find('#back').at(0).simulate('click'); expect(onBack).toHaveBeenCalled(); })
额外提醒
Enzyme和Testing Library可以配合用,但得拎清边界:Enzyme负责组件查询和模拟简单事件,而userEvent是模拟真实用户交互的,必须喂它原生DOM元素。另外,尽量少直接断言DOM属性,多测试组件的行为(比如回调调用、状态变化),这样测试会更健壮,不会因为DOM结构微调就挂掉。
内容的提问来源于stack exchange,提问作者Noname
相关产品推荐
相关产品推荐

