Hans Yulian
Hans Yulian

Reputation: 1170

Unit test inject dependency like controller for service in angularJS

Lets see, we have this according to:https://docs.angularjs.org/guide/unit-testing

describe('PasswordController', function() {
  beforeEach(module('app'));

  var $controller;

  beforeEach(inject(function(_$controller_){
    // The injector unwraps the underscores (_) from around the parameter names when matching
    $controller = _$controller_;
  }));

  describe('$scope.grade', function() {
    it('sets the strength to "strong" if the password length is >8 chars', function() {
      var $scope = {};
      var controller = $controller('PasswordController', { $scope: $scope });
      $scope.password = 'longerthaneightchars';
      $scope.grade();
      expect($scope.strength).toEqual('strong');
    });
  });
});

now i am making service and factory, is there any equivalent to ____$controller____ for service and factory? so i can inject it with something else like:

var controller = $controller('PasswordController', { $scope: $scope });

and change the inner functions of the dependency so i can test it, or is there any better approach?

Edit: to make question more clear here is the example of the question:

i have this:

var app = angular.module("app").service("MyService",["$scope","$http",function($scope,$http){
    this.myFunction = function(){
        $http.get("/myApi/1");
    }
}]);

how do i use the equivalent of

var controller = $controller('PasswordController', { $scope: $scope });

so i can inject $scope and $http with something else to myService?

Upvotes: 1

Views: 119

Answers (2)

Hans Yulian
Hans Yulian

Reputation: 1170

After doing a workarround, i found out from https://www.sitepoint.com/unit-testing-angularjs-services-controllers-providers/ about the service. i tested out the tutorial here and here is the test script:

(function () {
    angular.module('services', [])
        .service('sampleSvc', ['$window', 'modalSvc', function ($window, modalSvc) {
            this.showDialog = function (message, title) {
                if (title) {
                    modalSvc.showModalDialog({
                        title: title,
                        message: message
                    });
                } else {
                    $window.alert(message);
                }
            };
      }]);
    describe("Testing service", function () {
        var mockWindow, mockModalSvc, sampleSvcObj;
        beforeEach(module(function ($provide) {
                $provide.service('$window', function () {
                    this.alert = jasmine.createSpy('alert');
                });
                $provide.service('modalSvc', function () {
                    this.showModalDialog = jasmine.createSpy('showModalDialog');
                });
            }, 'services'));

        beforeEach(inject(function ($window, modalSvc, sampleSvc) {
            mockWindow = $window;
            mockModalSvc = modalSvc;
            sampleSvcObj = sampleSvc;
        }));
        it('should show alert when title is not passed into showDialog', function () {
            var message = "Some message";
            sampleSvcObj.showDialog(message);

            expect(mockWindow.alert).toHaveBeenCalledWith(message);
            expect(mockModalSvc.showModalDialog).not.toHaveBeenCalled();
        });

        it('should show modal when title is passed into showDialog', function () {
            var message = "Some message";
            var title = "Some title";
            sampleSvcObj.showDialog(message, title);

            expect(mockModalSvc.showModalDialog).toHaveBeenCalledWith({
                message: message,
                title: title
            });
            expect(mockWindow.alert).not.toHaveBeenCalled();
        });
    });
})();

and i try my own test script:

(function () {
    describe("Testing service", function () {
        var mockHttp, mockCookies, mockApi;
        beforeEach(function () {
            module(function ($provide) {
                $provide.service('$http', function () {
                    this.defaults = {
                        headers: {
                            common: {

                            }
                        }
                    };
                });
                $provide.service('$cookies', function () {

                });
            });
            module('timesheet');
        });

        beforeEach(inject(function ($http, $cookies, APIService) {
            mockHttp = $http;
            mockCookies = $cookies;
            mockApi = APIService;
        }));
        it('Test Service', function () {

        });
    });
})();

apparently in somewhere in my code, there is an app.run which inside do the

$http.defaults.headers.common.Authorization = 'Bearer ' + $cookies.get('sessionToken');

and causes the error the moment i inject the $http with something else because headers not defined, i thought it was from my own test script because they are using same name, but apparently this is the one causing problem.

So, actually the moment we load in testing mode, the angularjs still do the whole running of application, in which i forgot about this one.

Upvotes: 1

Max Koretskyi
Max Koretskyi

Reputation: 105439

You can't inject dependencies to factories or services on the go, but you can mock the dependencies with your custom objects and have angular substitute them automatically. You can use $provide for that. Here is an example:

angular.module('app').service('some', function(dependencyService) {

});

When testing:

beforeEach(module(function($provide) {
   $provide.value('dependencyService', {

   });
}));

Upvotes: 2

Related Questions