I am attempting to trigger the $scope.$on()
method in a controller that is fired when I $rootScope.broadcast()
an event. I found this question useful: How can I test events in angular?, but I'm still having trouble detecting an event being broadcast from the $rootScope
up through a controller's $scope
.
So far I've managed to test that the $broadcast
method is called on a corresponding $rootScope
, but not that the $on
method was called on a corresponding $scope
when $broadcast
is called on the $rootScope
.
I attempted to $rootScope.$broadcast
directly in my test, but my spy is not picking up on the event.
This is my controller:
angular.module('app.admin.controllers.notes', [])
.controller('NotesCtrl', function($scope) {
$scope.$on('resource-loaded', function(event, resource) { // I want to test this
$scope.parentType = resource.type;
$scope.parentId = resource.id;
});
});
This is my test:
describe('The notes controller', function() {
beforeEach(module('app.admin.controllers.notes'));
var scope, rootScope, NotesCtrl;
beforeEach(inject(function($controller, $injector, $rootScope) {
rootScope = $rootScope;
scope = $rootScope.$new(); // I've tried this with and without $new()
NotesCtrl = $controller('NotesCtrl', {$scope: scope}); // I've tried explicitly defining $rootScope here
}));
it('should respond to the `resource-loaded` event', function() {
spyOn(scope, '$on');
rootScope.$broadcast('resource-loaded'); // This is what I expect to trigger the `$on` method
expect(scope.$on).toHaveBeenCalled();
});
});
And here's the plunkr. I've included a passing test of the $broadcast
method for reference, mainly because I setup the tests in the same manner.
I've read quite a few questions relating to testing events in AngularJS, and it always seems to be a scoping issue. I've heard that in Karma unit testing, $rootScope
and $scope
are the same thing, but I'm not really sure what the implication is. I've tried defining the $rootScope
and the $scope
as the same object, as well as explicitly injecting the $rootScope
into the NotesCtrl
during testing, but nothing makes my test go green.
How can I get the $on
method in my NotesCtrl
to fire for this test?
According to the Angular Testing documentation, to trigger the events from the tests, we use the triggerEventHandler() method on the debug element. This method takes the event name and the object . Now, this works if we are adding the events using the HostListener .
For click event we can use triggerEventHandler method of Angular DebugElement class. We can also call native JavaScript click method of button. On click of button, we call a component method and it is possible that our component method has other dependencies to execute.
What makes it not working is the fact that you're spying the $on
function. It works fine when not sying it: http://plnkr.co/edit/hNEj7MmDDKJcJ7b298OB?p=info. And the reason is actually simple. When an event is brodcasted, what is called is not the $on()
function. What is called is the callback function passed as argument to $on()
previously: the listener.
Note that, by spying the $on function, you're not testing your code here. All you're trying to test is that when broadcasting en event, child scopes receive it. So you're testing AngularJS itself.
Try to use
$rootScope.$emit('resource-loaded');
Works fine in my tests.
@kirill.buga
Using $broadcast is right, not $emit because :
https://docs.angularjs.org/api/ng/type/$rootScope.Scope Dispatches an event name upwards through the scope hierarchy notifying the registered $rootScope.Scope listeners.
Problem of @ben-harold is trying to spy $on instead of the result of code in the $on.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With