21

How do I test that the scope is populated after the broadcast? I've searched and found a few QA's here in stackexchange, but none answered my problem. The code is working alright, just don't know how to test it. May I add that I'm a novice to testing, and especially with Jasmine.

So, here's the code:

Service CrappySvc:

update: function() {
    $rootScope.$broadcast('updatecrappy', Crappy.query());
}   

Controller GetCrappyCtrl:

  $scope.$on('updatecrappy', function(event, crap) {
    $scope.crap = crap;
  });

Jasmine:

beforeEach(inject(function($rootScope, $httpBackend, $controller, Crappy) {
  rootScope = $rootScope;
  scope = $rootScope.$new();
  Crappy = mockCrappy;

      ...
  spyOn(rootScope, '$broadcast');
      ...

  ctrl = $controller('GetCrappyCtrl', {
  $scope : scope,
  Crappy : mockCrappy
});               

}));

it('$scope.$on should have been triggered', function() {          
  rootScope.$broadcast('updatecrappy', [{id : 2, name : 'crappy'}]);
  expect(rootScope.$broadcast).toHaveBeenCalledWith('updscenes', [{id : 2, name : 'crappy'}]);

});

Stone

1

4 Answers 4

36

You need to tell Jasmine to let the spy call the actual $broadcast function

spyOn($rootScope, '$broadcast').andCallThrough();

If you don't use andCallThrough() the spy does nothing.

Jasmine Docs

EDIT

With Jasmine 2, the syntax would be

spyOn($rootScope, '$broadcast').and.callThrough();
Sign up to request clarification or add additional context in comments.

6 Comments

can we elaborate on what this is actually doing?
@whitebox That's the thing, it's not really doing much. By default, Jasmine's spies will replace the original function that is being spied on. Calling and.callThrough() will add to the default behaviour and cause the spy to also call the original function that was being spied on. And that's really all that it does.
you don't need the and.callThrough() in this case if you are just asserting the broadcast was called
does mocha have anything like .callThrough
As far as I know mocha does not come with its own spy-functionality so that would depend on which library you use for mocking.
|
0

If want to fake the returnValue from $scope.$broadcast() you can do something like these two cases:

Case 1:

scope.$broadcast('TEST_CHANGED', {test: 'test1'});
spyOn(scope, '$broadcast').and.callThrough();
expect(something).toEqual('something');

Case 2:

scope.$broadcast('TEST_CHANGED', {test: 'test2'});
spyOn(scope, '$broadcast').and.callThrough();
expect(something2).toEqual('something2');

Comments

0

As far as "toHavebeenCalled" concerned, there is no need of "andCallThrough()". Simple spy would work. In your case your arguments are different.

You are broadcasting like, rootScope.$broadcast('updatecrappy', [{id : 2, name : 'crappy'}]);

But you expect :

expect(rootScope.$broadcast).toHaveBeenCalledWith('updscenes', [{id : 2, name : 'crappy'}]);

look at argument " updarecrappy" but in tohavebeencalled it is "updscenes".

Comments

0

Look at the sample code below, it works well for me.

Emitting sample event 'onTimeChanged' from $rootScope. My controller has a listener 'onTimeChanged' and I am calling a method timeChanged() inside it.

describe('onTimeChanged()', function() {
    it('should call another method or controller', function() {
        spyOn(searchCtrl, 'timeChanged');
        $rootScope.$emit('onTimeChanged');
        expect(searchCtrl.timeChanged).toHaveBeenCalled();
    });
});

Note that I did not spy on method '$emit' of rootScope.

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.