Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit test Angular controller with $scope.$on?

I have a controller with an event listener in my Angular app, defined as follows.

  angular.module('test').controller('TestCtrl', function($rootScope, $scope, testService) {

    [...]

    $scope.$on("myEvent", function(args, value) {
      testService.doStuff(value);
    });
  });

This works perfectly in the app itself. However, when I try to unit test the functionality of the controller (using Jasmine and Karma), each test method throws the following error:

 TypeError: $scope.$on is not a function in [...]/testController.js

I create the controller in my test methods as follows.

  it('does stuff', inject(function($rootScope, $controller, testService) {
    var scope = $rootScope.$new;
    $controller('TestCtrl', {
      $scope : scope
    });

    [...]
  }));

I can get around the problem by changing my controller to use rootScope instead:

  $rootScope.$on(...)

but then of course the app doesn't work anymore as expected. I can also get rid of the error by introducing the $on method in my test code:

  var scope = $rootScope.$new;
  scope.$on = function() {};

but mocking the listener like this kind of defeats the purpose of testing my real code.

Why doesn't the test code find the $on method of the scope? (But finds it on rootScope, still...)

There must be something fundamental that I'm missing here but I haven't been able to figure it out even after lots of googling and reading the Angular source code.

like image 481
MJV Avatar asked May 21 '13 13:05

MJV


People also ask

Is there a unit testing tutorial for angular?

Editor’s note: This tutorial was last updated on December 31, 2020. In this Angular unit testing tutorial, we’ll demonstrate how to build a simple Angular app and then walk through the unit testing process step by step with examples.

What is the best excuse for not testing AngularJS?

With AngularJS, there is no excuse for not testing. Separation of Concerns Unit testing, as the name implies, is about testing individual units of code. Unit tests try to answer questions such as "Did I think about the logic correctly?"

Do I need to test my AngularJS application?

For this reason we feel very strongly that any code written in JavaScript needs to come with a strong set of tests. We have built many features into AngularJS which make testing your AngularJS applications easy. With AngularJS, there is no excuse for not testing. Separation of Concerns

What are the different types of angular testing?

There are two types of Angular testing: Unit testing is the process of testing small, isolated pieces of code. Also known as isolated testing, unit tests do not use external resources, such as the network or a database


1 Answers

$rootScope.$new is a function. You need to invoke it ($rootScope.$new()):

it('does stuff', inject(function($rootScope, $controller, testService) {
  var scope = $rootScope.$new();
  $controller('TestCtrl', {
    $scope : scope
  });

  [...]
}));

Example plunk: http://plnkr.co/edit/t1x62msmOQDkNItGzcp9?p=preview

like image 116
Matt York Avatar answered Sep 22 '22 07:09

Matt York