63

I have a controller which emits a broadcast event on the rootscope. I would like to test that the broacast event is fired correctly.

My code in my controller looks like this:

   $scope.$watch("pageIndex", function(){
    if($scope.pageIndex == 4)
    {
      // emit social share
      $rootScope.$broadcast('myEvent');
    }
  });

I have tried to test it with the following code:

    it('Should call myEvent when pageIndex is 4',function(){
    scope.pageIndex = 4;
    scope.$apply();
    expect(rootScope.$on).toHaveBeenCalledWith('myEvent');
});

But it tells me that the code isn't called, which I have manually tested that it does. I have then tried with the following code:

it('Should call myEvent when pageIndex is 4',function(){
    var listener = jasmine.createSpy('listener');
    rootScope.$on('myEvent', listener);
    scope.pageIndex = 4;
    scope.$apply();
    expect(listener).toHaveBeenCalled();
});

But with the same negative result. Is there a way to test that an event is broadcasted?

Dofs
  • 17,737
  • 28
  • 75
  • 123

2 Answers2

117

Assuming you're using Jasmine, the following is working great for me.

... other unit test setup code ...

var rootScope;
beforeEach(inject(function($injector) {
    rootScope = $injector.get('$rootScope');
    spyOn(rootScope, '$broadcast');
}));

describe("my tests", function() {
    it("should broadcast something", function() {
        expect(rootScope.$broadcast).toHaveBeenCalledWith('myEvent');
    });
});

If you're broadcasting a message and attaching objects to it, you can even test that the objects match expectations

someObj = { ... something ... };
expect(rootScope.$broadcast).toHaveBeenCalledWith('someEvent', someObj);
Mike Pugh
  • 6,787
  • 2
  • 27
  • 25
  • @Mike: Any way you can show an example of this solution with Mocha/Chai? – Ryan Conaway Mar 28 '14 at 22:27
  • @RyanConaway - for Chai it looks like you'll need a spy plugin such as https://github.com/chaijs/chai-spies . For Mocha, check out http://sinonjs.org/. The documentation for both of those are pretty clear on how you'd achieve this solution with either library. – Mike Pugh Mar 30 '14 at 00:11
  • 1
    How does one test that multiple calls with different arguments? – BrightIntelDusk Jul 28 '14 at 15:17
  • 2
    @IntegrityFirst - just create more expectations (preferably in their own isolated tests) – Mike Pugh Jul 29 '14 at 17:24
  • how can we do the same with mocha-chai? I am getting error as spyOn not defined. – Mayank Oct 12 '15 at 11:44
  • @mayank see my answer to Ryan Conaway above. – Mike Pugh Oct 12 '15 at 14:56
  • If you are broadcasting a message and attaching a objects, and if you don't want to specify the exact object: `expect(rootScope.$broadcast).toHaveBeenCalledWith('someEvent', jasmine.anything());` – Sudarshan_SMD Jul 21 '16 at 08:33
12

Here's how its done with mochaJs, with sinon for mocks and chai for expectations.

describe("broadcast test", function() {
  beforeEach(inject(function($rootScope){
   sinon.spy($rootScope, "$broadcast")
   scope.foo() //this broadcasts the event. $rootScope.$broadcast("testEvent")
 }))

it("broadcasts the event", inject(function($rootScope){
 expect($rootScope.$broadcast.calledWith("testEvent")).to.be.true
}))

})
Sudhir N
  • 4,008
  • 1
  • 22
  • 32