How can I test events in angular?

42,314

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.

Share:
42,314
Kenneth Lynne
Author by

Kenneth Lynne

Systems Consultant and web-fanatic from Norway

Updated on July 08, 2022

Comments

  • Kenneth Lynne
    Kenneth Lynne almost 2 years

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

    What's the best way to do this?

  • Luke Madera
    Luke Madera over 10 years
    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?
  • Ricardo Pedroni
    Ricardo Pedroni over 9 years
    @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.
  • Cameron
    Cameron over 9 years
    Thanks, but would there be a way to use jasmine? Something like: expect(scope.$emit.calls.argsFor(0)[0]).toBe('MY_EVENT_ID');
  • Karthik Balakrishnan
    Karthik Balakrishnan almost 9 years
    @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?
  • a7omiton
    a7omiton almost 9 years
    @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.