Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing named function within a Controller

A newbie Jasmine/Angular question.

I have a named function within a controller like so:

.controller( 'DummyCtrl', function DummyCtrl($scope){
   var doSomething = function() {
      return "blah";
   };
})

I need to test this function, and am trying to by calling the following Jasmine spec:

describe ('myApp', function(){
  var $scope, $controller;
  var DummyCtrl;

  beforeEach(module('myApp'));

  describe('controllers', function(){
    beforeEach(inject(function ($controller, $rootScope){
      $scope = $rootScope.$new();
      DummyCtrl = $controller('DummyCtrl', {$scope: $scope});
    }));

    describe( 'DummyCtrl', function(){
            var blah;

            beforeEach(function(){
                blah = DummyCtrl.doSomething();
            });

            it('should do something', function(){
                expect(blah).toContain("blah");
            });
    });
  });
});

Instead of things working out, I result in the following error: TypeError: Object #<DummyCtrl> has no method 'doSomething'. I'm assuming this is something super simple that I'm not understanding.

like image 725
jbenowitz Avatar asked Jun 18 '13 22:06

jbenowitz


2 Answers

The function DummyCtrl you are providing for the controller registration will be used by Angular as a constructor. If you need the controller instance to expose the function doSomething without attaching it to the $scope, you should attach it to this.

Try changing

var something = function(...

to

this.something = function(...

and your test should work.

You can see this approach here: http://jsfiddle.net/yianisn/8P9Mv/. Also have a look at this SO question: How to write testable controllers with private methods in AngularJs?

like image 71
yianis Avatar answered Oct 11 '22 12:10

yianis


In a sense, using functions like that is private, and cannot be accessed from outside the function. Take a look at this link: http://javascript.crockford.com/private.html

Essentially what is said is that have a function/object in javascript, anything with a this. prefix is public, and anything with a var prefix is private.

For Angular, you can definitely have private variables and functions, if not just to lessen the memory usage of the $scope variable. Private functions should be called by your $scope objects to get values to be displayed/used by the user. Try changing it to this:

.controller( 'DummyCtrl', function DummyCtrl($scope){
   var doSomething = function() {
      return "blah";
   };
   $scope.something=doSomething();
})

And then testing the private function with:

describe( 'DummyCtrl', function(){
    var scope = {},
        ctrl = new DummyCtrl(scope);
    it('should do something', function(){
        expect(scope.something).toMatch('blah');
    });
});
like image 42
Tim Withers Avatar answered Oct 11 '22 11:10

Tim Withers