67

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,753
  • 72
  • 57
  • 129
Kenneth Lynne
  • 15,461
  • 12
  • 63
  • 79

3 Answers3

120

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

starball
  • 20,030
  • 7
  • 43
  • 238
dnc253
  • 39,967
  • 41
  • 141
  • 157
  • 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');` – Cameron 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,410
  • 1
  • 16
  • 24
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
  • 163
  • 1
  • 13