Подтвердить что ты не робот

Как написать тест FileReader в 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('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.

4b9b3361

Ответ 1

Проблема заключается в использовании 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

Этот синтаксис изменился в версии 2.0. В приведенном ниже коде приведен пример, основанный на ответе Андреаса Кёберле, но использующий новый синтаксис

    // 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);

Ответ 3

Мне было легче всего сделать следующее.

  • mock blob file
  • запустить reader.onload в тестовой среде.

как результат - я не издеваюсь над Filereader

//    CONTROLLER

$scope.handleFile = function (e) {

            var f = e[0];

            $scope.myFile = {
                name: "",
                size: "",
                base64: ""
            };
            var reader = new FileReader();
            reader.onload = function (e) {
                        try {
                            var buffer = e.target.result;
                            $scope.myFile = {
                                name: f.name,
                                size: f.size,
                                base64: XLSX.arrayBufferToBase64(buffer)
                            };
                            $scope.$apply();

                        } catch (error) {
                            $scope.error = "ERROR!";
                            $scope.$apply();
                        }
                    };

reader.readAsArrayBuffer(f);
//run in test env
if ( typeof jasmine == 'object') {reader.onload(e)}
}

//JASMINE TEST

it('handleFile    0', function () {


    var  fileContentsEncodedInHex = ["\x45\x6e\x63\x6f\x64\x65\x49\x6e\x48\x65\x78\x42\x65\x63\x61\x75\x73\x65\x42\x69\x6e\x61\x72\x79\x46\x69\x6c\x65\x73\x43\x6f\x6e\x74\x61\x69\x6e\x55\x6e\x70\x72\x69\x6e\x74\x61\x62\x6c\x65\x43\x68\x61\x72\x61\x63\x74\x65\x72\x73"];
    var blob = new Blob(fileContentsEncodedInHex);
    blob.type = 'application/zip';
    blob.name = 'name';
    blob.size = 11111;
    var e = {0: blob, target: {result: {}}};

    $scope.handleFile(e);
    expect($scope.error ).toEqual("");

});

Ответ 4

Я также столкнулся с подобной проблемой и смог достичь ее без использования 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();
    });

Таким образом, вы смоделировали объект FileReader и вернули ложный вызов своему собственному "readAsDataURL". И, следовательно, теперь, когда ваш реальный код вызывает "reasAsDataURL", вызывается ваша фальшивая функция, в которой вы присваиваете закодированную строку в "результате" и вызываете функцию "onloadend", которой вы уже присвоили функциональность в своем файле кода (.ts). И поэтому он вызывается с ожидаемым результатом. Надеюсь, поможет.