66

I need to test that events get correctly emitted or broadcast, and trigger events manually.

What's the best way to do this?

Brian Tompsett - 汤莱恩
  • 5,438
  • 68
  • 55
  • 126
Kenneth Lynne
  • 15,147
  • 12
  • 60
  • 76

3 Answers3

121

If you're just needing some testing on event firing and catching, this is how I do it. For ensuring that a certain event gets fired ($emit-ed or $broadcast-ed), a spy is the way to go. You need a reference to the scope that will be calling the $emit or $broadcast, and then just to do something like this:

spyOn(scope, "$emit")
//run code to test
expect(scope.$emit).toHaveBeenCalledWith("MY_EVENT_ID", other, possible, args);

If you don't need or don't want to worry about the arguments that are passed with the $emit, you can put an $on on the $rootScope and set a flag to know the event was emitted. Something like this:

var eventEmitted = false;
$rootScope.$on("MY_EVENT_ID", function() {
   eventEmitted = true;
});
//run code to test
expect(eventEmitted).toBe(true);

For testing functionality that runs when an event is caught ($on), it's a little easier. Just get a $rootScope from the inject function and then send the desired event.

$rootScope.$broadcast("EVENT_TO_TEST", other, possible, args);
//expects for event here

Now, I imagine this event handling would be happening in a directive or a controller (or both) For setting up directive tests, see https://github.com/vojtajina/ng-directive-testing. For setting up controller tests, see https://github.com/angular/angular-phonecat/blob/master/test/unit/controllersSpec.js#L27

Hope this helps.

dnc253
  • 39,177
  • 38
  • 137
  • 153
  • This is good for exact matches but how would one match a subset of arguments? For example if the args are just one object {p1:'yes', p2:'no'} how would you expect that p1:'yes' no matter what p2 is (or if it event exists)? I know there's the 'any' jasmine keyboard but that seems to be the opposite - not fine grained enough control. Any middle ground where you can expect just the args you want? – Luke Madera Dec 21 '13 at 06:48
  • @LukeMadera Jasmine has `jasmine.objectContaining`. From the docs: jasmine.objectContaining is for those times when an expectation only cares about certain key/value pairs in the actual object. – Ricardo Pedroni Nov 17 '14 at 14:06
  • Thanks, but would there be a way to use jasmine? Something like: `expect(scope.$emit.calls.argsFor(0)[0]).toBe('MY_EVENT_ID');` – cameronroe Jan 18 '15 at 17:47
  • @dnc253 I have a parent node listening for `$emit` events. My tests pass only when I use `$rootScope.$broadcast` and then check for events, they don't pass for `$rootScope.$emit`, is this because `$emit` can only traverse up the node and not itself and to the children nodes? – Karthik Balakrishnan Jul 15 '15 at 08:19
  • @cameronjroe a bit late, but I believe using `toHaveBeenCalledWith` is suitable even to just check if an event was fired. This is because the event name is an argument for `$emit`, so here the test would make sense. – a7omiton Jul 22 '15 at 13:19
0

Here are the steps you should follow to $broadcast event in angular JS

While inijecting initialize the rootScope and scope stub as given below:

var rootScope;
var scopeStub = beforeEach(function() {
    inject(function($rootScope, _$controller_) {
        rootScope = $rootScope;
        scopeStub = $rootScope.$new();
        $controller = _$controller_;
    });
});

After controller is created raise event using rootScope like below:

rootScope.$broadcast('eventName', parameter1);
Dilip Nannaware
  • 1,350
  • 1
  • 14
  • 23
0

We used this sintax for A1

=========== Controller ========
    var vm = this;
    $scope.$on('myEvent', function(event, data){
        console.log('event number', data.id);
    });
============ Test =============
 it('should throw myEvent', function() {
    var data = {};
    $scope.$broadcast('myEvent', {id:1});
    $scope.$broadcast('myEvent', {id:2});
    $scope.$broadcast('myEvent', {id:3});
});

============ Output ============
Chrome LOG: '--------------------------------------------'
Chrome LOG: 'event number', 1
Chrome LOG: 'event number', 2
Chrome LOG: 'event number', 3
Jnewbie
  • 155
  • 1
  • 11