3
votes

i'm trying to unit test a controllers method in Angularjs that is responsible for file upload:

 $scope.uploadFile = function() {
    var fd = new FormData();
    for (var i in $scope.files) {
        fd.append("uploadedFile", $scope.files[i]);
    }
    var xhr = new XMLHttpRequest();
    xhr.addEventListener("load", $scope.uploadComplete, false);
    xhr.addEventListener("error", uploadFailed, false);
    xhr.open("POST", "/fileupload");
    xhr.send(fd);
}

i tried to mock the xhr object like the following :

it("using $window ", inject(function($window) {
$window.XMLHttpRequest= angular.noop;
addEventListenerSpy = jasmine.createSpy("addEventListener");
openSpy = jasmine.createSpy("open");
sendSpy = jasmine.createSpy("send");
xhrObj = {
   upload: 
   {
       addEventListener: addEventListenerSpy
   },
   addEventListener: addEventListenerSpy,
   open: openSpy,
   send: sendSpy
};
spyOn($window, "XMLHttpRequest").andReturn(xhrObj);

}));

when i run karma test config file i have the following error :

TypeError: Attempted to assign to readonly property. at workFn (/home/dre/trunk/app/bower_components/angular-mocks/angular-mocks.js:2107)

can anyone help me i'm new in unit testing with jasmine and karma

1

1 Answers

1
votes

You should be using Angular dependency injection which greatly helps tests. You should also use Angular's $http or $resource service to perform XHR requests.

Having said that, I created a fiddle with your test. Test implementation are missing in your question, e.g. controller creation. I hope the full example gives you a clue as to the problem in your code.

it("using $window ", function () {
    xhrObj = jasmine.createSpyObj('xhrObj', 
                                  ['addEventListener', 'open', 'send']);
    spyOn(window, "XMLHttpRequest").andReturn(xhrObj);

    scope.uploadFile()

    expect(xhrObj.addEventListener).toHaveBeenCalled();
    expect(xhrObj.addEventListener.calls.length).toBe(2);
});

You can find the full example here.

But I urge you to use $http/$resource instead.