Javascript 如何用Jasmine编写文件阅读器测试?

Javascript 如何用Jasmine编写文件阅读器测试?,javascript,html,unit-testing,jasmine,Javascript,Html,Unit Testing,Jasmine,我试图让这个测试正常工作,但我不知道如何用FileReader编写测试。这是我的密码 function Uploader(file) { this.file = file; } Uploader.prototype = (function() { function upload_file(file, file_contents) { var file_data = new FormData() file_data.append('filen

我试图让这个测试正常工作,但我不知道如何用FileReader编写测试。这是我的密码


function Uploader(file) {
    this.file = file;
}

Uploader.prototype =  (function() {

    function upload_file(file, file_contents) {
        var file_data = new FormData()
        file_data.append('filename', file.name)
        file_data.append('mimetype', file.type)
        file_data.append('data', file_contents)
        file_data.append('size', file.size)

        $.ajax({
            url: "/upload/file",
            type: "POST",
            data: file_contents,            
            contentType: file.type,
            success: function(){

                // $("#thumbnail").attr("src", "/upload/thumbnail");    

            },
            error: function(){
                alert("Failed");
            },
            xhr: function() {
                myXhr = $.ajaxSettings.xhr();
                if(myXhr.upload){
                    myXhr.upload.addEventListener('progress',showProgress, false);
                } else {
                    console.log("Upload progress is not supported.");
                }
                return myXhr;
            }
        });
    }

    return {
        upload : function() {
            var self = this,
                reader = new FileReader(),
                file_content = {};

            reader.onload = function(e) {
                file_content = e.target.result.split(',')[1];

                upload_file(self.file, file_content);
            }
        }
    };
})();


这是我的测试


describe("Uploader", function() {
    it("should upload a file successfully", function() {
        spyOn($, "ajax");
        var fakeFile = {};

        var uploader = new Uploader(fakeFile);
        uploader.upload();

        expect($.ajax.mostRecentCall.args[0]["url"]).toEqual("/upload/file");
    })
});

但是它永远不会到达
reader.onload
这里的问题是
reader.onload
的使用,这很难测试。您可以使用
reader.addEventListener
来监视全局FileReader对象并返回模拟:

eventListener = jasmine.createSpy();
spyOn(window, "FileReader").andReturn({
 addEventListener: eventListener
})
然后您可以自己启动onload回调:

expect(eventListener.mostRecentCall.args[0]).toEqual('load');
eventListener.mostRecentCall.args[1]({
  target:{
    result:'the result you wanna test'
  }
})

此语法在2.0中更改。下面的代码给出了一个基于Andreas Köberle的答案但使用新语法的示例

    // create a mock object, its a function with some inspection methods attached
    var eventListener = jasmine.createSpy();

    // this is going to be returned when FileReader is instantiated
    var dummyFileReader = { addEventListener: eventListener };

    // pipe the dummy FileReader to the application when FileReader is called on window
    // this works because window.FileReader() is equivalent to new FileReader()
    spyOn(window, "FileReader").and.returnValue(dummyFileReader)

    // your application will do something like this ..
    var reader = new FileReader();

    // .. and attach the onload event handler
    reader.addEventListener('load', function(e) {

        // obviously this wouldnt be in your app - but it demonstrates that this is the 
        // function called by the last line - onloadHandler(event);
        expect(e.target.result).toEqual('url');

        // jasmine async callback
        done();
    });

    // if addEventListener was called on the spy then mostRecent() will be an object. 
    // if not it will be null so careful with that. the args array contains the 
    // arguments that addEventListener was called with. in our case arg[0] is the event name ..
    expect(eventListener.calls.mostRecent().args[0]).toEqual('load');

    // .. and arg[1] is the event handler function
    var onloadHandler = eventListener.calls.mostRecent().args[1];

    // which means we can make a dummy event object .. 
    var event = { target : { result : 'url' } };

    // .. and call the applications event handler with our test data as if the user had 
    // chosen a file via the picker
    onloadHandler(event);

我发现自己下一步最容易做

  • 模拟blob文件
  • 在测试环境中运行reader.onload
因此,我不会模仿Filereader

//控制器
$scope.handleFile=函数(e){
var f=e[0];
$scope.myFile={
姓名:“,
大小:“,
base64:“
};
var reader=new FileReader();
reader.onload=函数(e){
试一试{
var buffer=e.target.result;
$scope.myFile={
姓名:f.name,
尺寸:f.size,
base64:XLSX.arrayBufferToBase64(缓冲区)
};
$scope.$apply();
}捕获(错误){
$scope.error=“error!”;
$scope.$apply();
}
};
reader.readAsArrayBuffer(f);
//在测试环境中运行
if(typeof jasmine=='object'){reader.onload(e)}
}
//茉莉花试验
它('handleFile 0',函数(){
var fileContentsEncodedInHex=[“\x45\x6e\x63\x6f\x64\x65\x49\x6e\x48\x65\x78\x42\x65\x63\x61\x75\x73\x61\x62\x69\x6e\x61\x72\x79\x46\x69\x6c\x65\x73\x73\x63\x6f\x6e\x64\x61\x69\x65\x65\x64\x61\x61\x62\x62\x65\x61\x61\x61\x61\x61\x62\x61\x63\x61\x61\x63\x62\x62\x63\x62\x61”];
var blob=新blob(fileContentsEncodedInHex);
blob.type='application/zip';
blob.name='name';
blob.size=11111;
var e={0:blob,目标:{result:{};
$scope.handleFile(e);
expect($scope.error).toEqual(“”);

});我也面临类似的问题,并且能够在不使用addeventlistener的情况下实现它。我使用了onloadend,下面是我所做的。 我的ts文件包含以下代码:-

    let reader = new FileReader();
    reader.onloadend = function() {
                let dataUrl = reader.result;
                // Some working here
            };
    reader.readAsDataURL(blob);
我的规范文件(测试)案例代码:-

 let mockFileReader = {
            result:'',
            readAsDataURL:(blobInput)=> {
                console.log('readAsDataURL');
            },
            onloadend:()=> {
                console.log('onloadend');
            }
        };

    spyOn<any>(window, 'FileReader').and.returnValue(mockFileReader);
    spyOn<any>(mockFileReader, 'readAsDataURL').and.callFake((blobInput)=> {
        // debug your running application and assign to "encodedString" whatever 
        //value comes actually after using readAsDataURL for e.g. 
        //"data:*/*;base64,XoteIKsldk......"
        mockFileReader.result = encodedString;
        mockFileReader.onloadend();
    });
让mockFileReader={
结果:“”,
readAsDataURL:(blobInput)=>{
log('readAsDataURL');
},
onloadend:()=>{
log('onloadend');
}
};
spyOn(窗口,'FileReader')。和.returnValue(mockFileReader);
spyOn(mockFileReader,'readAsDataURL')。和.callFake((blobInput)=>{
//调试正在运行的应用程序,并将其分配给“encodedString”
//值实际上是在使用readAsDataURL之后出现的,例如。
//“数据:*/*;base64,XoteIKsldk…”
mockFileReader.result=encodedString;
mockFileReader.onloadend();
});
通过这种方式,您模拟了FileReader对象,并返回了对您自己的“readAsDataURL”的假调用。因此,现在当您的实际代码调用“reasAsDataURL”时,您的伪函数被调用,其中您在“result”中分配了一个编码字符串,并调用了“onloadend”函数,您已经在代码(.ts)文件中分配了一个功能。因此,它会被调用,并得到预期的结果。
希望能有所帮助。

当从
readAsDataURL
调用onloadend时,我努力想知道如何测试它。 这是一堆我最后得到的东西

生产代码:

测试代码:


我认为最好的方法是使用真正的
文件阅读器
(不要模仿它),并传入真正的
文件
Blob
。这提高了您的测试覆盖率,并使您的测试不那么脆弱

如果你的测试没有在IE中运行,你可以使用

const fakeFile=新文件([“某些内容”],“File.txt”,{type:“text/plain”});
如果您需要与IE兼容,您可以构造一个并使其看起来像一个文件:

const fakeFile=newblob([“某些内容]);
fakeFile.name=“file.txt”;
fakeFile.type=“text/plain”;

FileReader
可以读取这两个对象中的任何一个,因此无需对其进行模拟。

我对此束手无策。谁能提供一个有效的例子?我总是不确定(使用Karma/Angular/Jasmine)。这真的很过时。现在我认为最好不要嘲笑FileReader,请参见下面的答案。我发现,奇怪的是,如果你在全局范围内隐式创建FileReader,比如
new FileReader()
,Jasmine找不到它,但是,如果我调用
newwindow.FileReader()
,那么间谍就会像预期的那样出现。我花了将近一个小时才弄明白。@supertguy我恐怕不记得了。很抱歉我今天一直在努力解决这个问题,而你的解决方案确实让问题变得简单多了。谢谢如果要测试
onerror
路径,该怎么办?你会怎么做呢?我不确定这是否可能——你可能需要从其他答案中选择一种嘲弄的方法。
loadFileDataIntoChargeback(tempFileList) {
        var fileNamesAndData = [];
        for (var i = 0, f; f = tempFileList[i]; i++) {
            let theFile = tempFileList[i];
            var reader = new FileReader();
            reader.onloadend = ((theFile) => {
                return (fileData) => {
                    var insertionIndex = this.chargeback.fileList.length;
                    this.chargeback.fileList.push({ FileName: theFile.name, Data: fileData.target.result, FileType: theFile.type });
                    this.loadFilePreviews(theFile, insertionIndex);
                }
            })(f);
            reader.readAsDataURL(f);
        }
        this.fileInputPath = "";
    }
describe('when the files are loaded into the chargeback', () => {
            it('loads file previews', () => {
                let mockFileReader = {
                    target: { result: '' },
                    readAsDataURL: (blobInput) => {},
                    onloadend: () => {}
                };
                spyOn(chargeback, "loadFilePreviews");
                spyOn(window, 'FileReader').and.returnValue(mockFileReader);
                spyOn(mockFileReader, 'readAsDataURL').and.callFake((blobInput) => {
                    mockFileReader.onloadend({ target: { result: "data:image/jpeg;base64,/9j/4QAYRXh" } });
                });
                var readFileList = chargeback.getArrayFromFileInput([getImageFile1()]);

                chargeback.loadFileDataIntoChargeback(readFileList);

                expect(chargeback.loadFilePreviews).toHaveBeenCalled();
            });
        });