7

I have been trying to test a service to no avail for some time now and was hoping for some help. Here is my situation:

I have a service looking a little like this

myModule.factory('myService', ['$rootScope', '$routeParams', '$location', function($rootScope, $routeParams, $location) {

  var mySvc = {
    params: {}
  }

  // Listen to route changes.
  $rootScope.$on('$routeUpdate', mySvc.updateHandler);

  // Update @params when route changes
  mySvc.updateHandler = function(){ ... };

  ...
  ...

  return mySvc;

}]);

And I want to mock the services injected into 'myService' before the service gets injected into my tests so I can test the initialization code below

  var mySvc = {
    params: {}
  }

  // Listen to route changes.
  $rootScope.$on('$routeUpdate', mySvc.updateHandler);

I am using Jasmine for tests and mocks. This is what I came up with for now

describe('myService', function(){
  var rootScope, target;
  beforeEach(function(){
    rootScope = jasmine.createSpyObj('rootScope', ['$on']);

    module('myModule');
    angular.module('Mocks', []).service('$rootScope', rootScope );
    inject(function(myService){
      target = myService;
    });        
  });

  it('should be defined', function(){
    expect(target).toBeDefined();
  });

  it('should have an empty list of params', function(){
    expect(target.params).toEqual({});
  });

  it('should have called rootScope.$on', function(){
    expect(rootScope.$on).toHaveBeenCalled();
  });
});

This doesn't work though. My rootscope mock is not replacing the original and the Dependency Injection doc is confusing me more than anything.

Please help

2 Answers 2

7

I would spy on the actual $rootScope instead of trying to inject your own custom object.

var target, rootScope;
beforeEach(inject(function($rootScope) {
  rootScope = $rootScope;

  // Mock everything here
  spyOn(rootScope, "$on")
}));

beforeEach(inject(function(myService) {
  target = myService;
}));

it('should have called rootScope.$on', function(){
  expect(rootScope.$on).toHaveBeenCalled();
});

I've tested this in CoffeScript, but the code above should still work.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot! Worked like a charm. I can't believe I didn't try that before.
I had to add change spyOn(rootScope, "$on") to spyOn(rootScope, "$on").andCallThrough(); but worked great and got me going in the right direction.
0

You could create a RootController and then inject it:

inject(function(myService, $controller){
  target = myService;
  $controller('rootController', {
        $scope : $rootScope.$new(),
        $rootScope : myService
  });
});  

With this approach you can access $rootScope functions from your 'myService'; Such 'myService.$on()'

I just made it, let me know if help is needed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.