How can I test events in angular?
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.
Comments
-
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 over 10 yearsThis 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 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 over 9 yearsThanks, but would there be a way to use jasmine? Something like:
expect(scope.$emit.calls.argsFor(0)[0]).toBe('MY_EVENT_ID');
-
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 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.