user1024941 user1024941 - 3 months ago 13
AngularJS Question

Karma testing controller that calls service with http

Can someone please tell me the best way to run tests on my controller function getData and the factory function too. I've very confused and don't know where to start. How would you write tests for the code below?

myApp.controller('myController', ['$scope', 'myFactory', function ($scope, myFactory) {

$scope.getData = function(id) {
var promise = myFactory.GetData('/dta/GetData?Id=' + id);
promise
.then(function (success) {
$scope.result = success;
}, function (error) {
$scope.error = true;
});
}
});


myApp.factory('myFactory', ['$http', function ($http) {
return {
GetData: function (url) {
return $http.get(url)
.then(function (response) {
return response.data;
}, function (error) {
return error;
});
}
}
}]);

Answer

You'll want to test each component in isolation (that's what unit tests are for). So something like this for the controller

describe('myController test', () => {
    let scope, myFactory;

    beforeEach(() => {
        myFactory = jasmine.createSpyObj('myFactory', ['GetData']);            

        module('your-module-name');
        inject(function($rootScope, $controller) {
            scope = $rootScope.$new();

            $controller('myController', {
                $scope: scope,
                myFactory: myfactory
            });
        });
    });

    it('getData assigns result on success', inject(function($q) {
        let id = 1, success = 'success';
        myFactory.GetData.and.returnValue($q.when(success));

        scope.getData(id);
        expect(myFactory.GetData).toHaveBeenCalledWith('/dta/GetData?Id=' + id);
        scope.$digest(); // resolve promises
        expect(scope.result).toBe(success);
    }));

    it('getData assigns error on rejections', inject(function($q) {
        myFactory.GetData.and.returnValue($q.reject('error'));

        scope.getData('whatever');
        scope.$digest();
        expect(scope.error).toEqual(true);
    }));
});

For your factory, you would create a separate describe and inject and configure $httpBackend. There are plenty of example in the documentation.


FYI, you should omit the error handler in your factory, ie

return $http.get(url).then(response => response.data);

as you are currently converting a failed request into a successful promise.