I need to test that events get correctly emitted or broadcast, and trigger events manually.
What's the best way to do this?
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
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.expect(scope.$emit.calls.argsFor(0)[0]).toBe('MY_EVENT_ID');$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?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.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);
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