Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I trigger `$on` events in AngularJS Karma unit tests?

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?

like image 402
Ben Harold Avatar asked Oct 23 '14 21:10

Ben Harold


People also ask

How do you trigger event in Jasmine?

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 .

What is the correct way to trigger a click event on a button when testing an Angular component?

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.


3 Answers

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.

like image 71
JB Nizet Avatar answered Oct 24 '22 21:10

JB Nizet


Try to use

$rootScope.$emit('resource-loaded');

Works fine in my tests.

like image 29
kirill.buga Avatar answered Oct 24 '22 21:10

kirill.buga


@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.

like image 24
Emmanuel Dieval Avatar answered Oct 24 '22 20:10

Emmanuel Dieval