Testing Angular $ emit and $ for events

I am trying to write unit test for my events in the controller.

Below is my controller

myApp.controller('ParentCtrl', ['$scope', function ($scope) { $scope.message = "Some text in parent"; $scope.$on("update_parent_controller", function(event, message){ $scope.message = message; }); }]) .controller('ChildCtrl', ['$scope', function ($scope) { $scope.clickFunction = function() { $scope.message = "Parent updated from child controller"; $scope.$emit('update_parent_controller', $scope.message); } }]); 

And below is my test I'm trying to write

 describe("Hello Controller Test", function () { var ctrl, scope; beforeEach(module("myApp")); beforeEach(inject(function ($controller, $rootScope) { scope = $rootScope.$new(); spyOn(scope, '$on'); ctrl = $controller("ParentCtrl", { $scope : scope }); })); it('should change ParentCtrl message property from child ctrl', function (){ var new_hero = 'Ralf ninja turtle', sub_scope = scope.$new(); sub_scope.$emit('update_parent_controller', new_hero); expect(scope.$on).toHaveBeenCalled(); expect(scope.message).toBe('Ralf ninja turtle'); //Getting err here }); }); 

I expect the message in the parent controller to be updated, But the test fails while waiting (scope.message) .toBe ('Ralf ninja turtle');

+6
source share
2 answers

In the test case, scope.$on was noted.

 spyOn(scope, '$on'); 

To call a valid function, you need to add .and.callThrough() .

 spyOn(scope, '$on').and.callThrough(); 

Here is a complete working example:

 angular.module('myApp', []).controller('ParentCtrl', ['$scope', function ($scope) { $scope.message = "Some text in parent"; $scope.$on("update_parent_controller", function(event, message){ $scope.message = message; }); }]); describe("Hello Controller Test", function () { var ctrl, scope; beforeEach(module("myApp")); beforeEach(inject(function ($controller, $rootScope) { scope = $rootScope.$new(); spyOn(scope, '$on').and.callThrough(); // <-- This is the fix ctrl = $controller("ParentCtrl", { $scope : scope }); })); it('should change ParentCtrl message property from child ctrl', function (){ var new_hero = 'Ralf ninja turtle', sub_scope = scope.$new(); sub_scope.$emit('update_parent_controller', new_hero); expect(scope.$on).toHaveBeenCalled(); expect(scope.message).toBe('Ralf ninja turtle'); //Getting err here }); }); 
 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.4/jasmine.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.4/jasmine.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.4/jasmine-html.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.4/boot.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular-mocks.js"></script> 
0
source

You need to call $scope.$apply() after calling $emit . This will happen automatically in the application, but should be explicitly stated in the test.

+1
source

All Articles