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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 01:58:10