记一次测试文件上传功能踩坑

2,693 阅读2分钟

最近在写Vue uploader组件

基本功能完成后,开始着手写测试

于是卡在了 input file 触发 change的问题

  • 有问题就google吧! 放弃百度吧!

具体思路如下

如何往input里 设置文件呢?

let input = inputWrapper.element;
let file1 = new File(['xxx'],'xxx.txt');
let file2 = new File(['yyy'],'yyy.txt');
input.files[0] = file1;
input.files[1] = file2;


报错
TypeError: Failed to set an indexed property on 'FileList': Index property setter is not supported.
    at Context.eval (webpack-internal:///./tests/unit/uploader.spec.js:53:20)

意思不能这样给 input 设置文件

那就尝试把 input 的文件变成数组

input.files = [file1,file2];

结果又报错了

TypeError: Failed to set the 'files' property on 'HTMLInputElement': The provided value is not of type 'FileList'.

求助 google 了

  • google 搜索 js set files for input file 然后每个链接点进去
  • 得到答案

里面有句信息如—— e.dataTransfer.files;

  • 重点就是这个 dataTransfer
target.addEventListener('drop', (e) => {
  e.preventDefault();
  body.classList.remove('dragging');
  
  fileInput.files = e.dataTransfer.files;
});

最后给了一个链接

  • stackoverflow.com/questions/4…

  • 这就是答案所在(我也开始讨厌写缩写的人了,写缩写简直就是zz,完全看不懂含义,非常容易让正在思考的大脑短路一下)

const dT = new ClipboardEvent('').clipboardData || // Firefox < 62 workaround exploiting https://bugzilla.mozilla.org/show_bug.cgi?id=1422655
  new DataTransfer(); // specs compliant (as of March 2018 only Chrome)
dT.items.add(new File(['foo'], 'programmatically_created.txt'));
inp.files = dT.files;

<input type="file" id="inp">
  • 修改我们的代码
const data = new DataTransfer();
data.items.add(file1);
data.items.add(file2);
input.files = data.files;

通过 google get到的 如何用js触发 input[type="file"] 的change 事件

拷贝代码在jsbin运行

let input =  document.createElement('input');
input.type = 'file';
input.multiple = true;
let file1 = new File(['xxxxxxxxx'], 'xxx.txt');
let file2 = new File(['yyyyyyyyy'], 'yyy.txt');

input.addEventListener('change',()=>{
  console.log(input.files);
})
const data = new DataTransfer()
data.items.add(file1)
data.items.add(file2);
input.files = data.files;

完美运行。把正确代码挪到测试代码里!悲剧发生了。

  • 死活不触发 change 事件,而在 jsbin 里 运行正常。卡了一下午都没找到答案
  • 继续 google (google就是神器啊!)
  • 搜索 input file trigger change
  • get到答案
  • 如果js里不触发事件,你就构造个事件对象来模拟触发吧!
it('可以上传一个文件', () => {
    const wrapper = mount(Uploader,{
        propsData: {
            name:'file',
            action:'/upload',
            method:'post',
            parseResponse:()=>{},
            fileList:[],
        },
        slots:{
            default:`<button id="xxxx">上传</button>`,
        },
        listeners:{
            'update:fileList':(fileList)=>{
                wrapper.setProps({fileList})
            }
        }
    });

    console.log(wrapper.html())
    wrapper.find('#xxxx').trigger('click');
    console.log(wrapper.html())  // 点击 button会创建一个 input[type="file"] 步骤正确执行

    let inputWrapper = wrapper.find('input[type="file"]');
    let input = inputWrapper.element;
    let file1 = new File(['xxxxxxxxx'], 'xxx.txt');
    let file2 = new File(['yyyyyyyyy'], 'yyy.txt');
    
    input.addEventListener('change',()=>{
        console.log('change~~~~');
    });
    const data = new DataTransfer();
    data.items.add(file1)
    data.items.add(file2);
    input.files = data.files;
    // 解决 input.files 设置后 死活不触发 change事件
    // google 搜索 input file trigger change
    // 答案参考 https://gist.github.com/Lochlan/ccbe22e7c5e80b6d7966
    var event = document.createEvent("UIEvents");
    event.initUIEvent("change", true, true);
    input.dispatchEvent(event);
});

结论

虽然无法解释为什么在 jsbin里 完美运行,但在 测试文件里 就不触发 input的change,但经过一通 google 依旧解决了问题!

  • 有问题就 google 吧!
  • 会一点英语的重要性