Maeh
Maeh

Reputation: 1764

AngularJS Jasmine, test function in controller

I am trying to test my AngularJS controller function using Jasmine. However, I am getting TypeError: undefined is not a function.

This is what the test looks like:

describe('BoardController', function() {

    beforeEach(module('examtesting'));

    var BoardController;

    beforeEach(inject(function($rootScope, $controller) {

        var scope = $rootScope.$new();

        BoardController = $controller('BoardController', { 
            $scope: scope,
            board: null,
            BoardService: null
        });

    }));


    it ("should toggle create_active", function() {
        var category = { create_active: false }

        BoardController.toggleCreateActive(category);

        expect(category.create_active).toBe(true);
    });

});

And here's the function I am trying to test:

    $scope.toggleCreateActive = function(category) {
        category.create_active = !category.create_active;
    }

What am I doing wrong?

Upvotes: 1

Views: 2226

Answers (3)

ronapelbaum
ronapelbaum

Reputation: 1797

When you use $scope, all your model is on scope, and the controller is just the controller...

Testing controller with controllerAs

After we’ve seen how to test a service, let’s talk about testing a controller.

function MyController(MyService) {
 this.greetUpperCase = function(name) {
  return MyService.greet(name).toUpperCase();
 }
}

We’d like angular’s DI to inject an instance of our controller to our test, but controllers are not singltons as services.

Therefore, we will:

inject the $controller service use it to instance a controller for us

var $controller;
beforeEach(module('MyModule'));
beforeEach(inject(function(_$controller_) {
    $controller = _$controller_; })
);
it('test greetUpperCase()', function() {
    var ctrl = $controller('MyController');
    expect(ctrl.greetUpperCase('bob')).toBe('HELLO BOB');
});

https://jsfiddle.net/ronapelbaum/tcmsw688/

Testing controller with $scope

Now, if you’re still workng with $scope:

function MyController($scope, MyService) {
 $scope.greetUpperCase = function(name) {
  return MyService.greet(name).toUpperCase();
 }
}

Basically, when you’re working with $scope, you don’t really care about the controller itself, since it’s doing everything on it’s scope.

So, we will need to:

inject $rootScope create a new scope inject it to a new controller test the $scope

it('test greetUpperCase()', function() {
 var myScope = $rootScope.$new();
 $controller('MyController', {
  $scope: myScope
 });
 expect(myScope .greetUpperCase('bob')).toBe('HELLO BOB');
});

https://jsfiddle.net/ronapelbaum/pkhaxmdg/

Upvotes: -1

wachme
wachme

Reputation: 2337

This should work:

describe('BoardController', function() {

    beforeEach(module('examtesting'));

    var createController, scope;

    beforeEach(inject(function($rootScope, $controller) {
        scope = $rootScope.$new();

        createController = function() {
            return $controller('BoardController', { 
                $scope: scope,
                board: null,
                BoardService: null
            });
        };
    }));


    it ("should toggle create_active", function() {
        var category = { create_active: false },
            controller = createController();

        scope.toggleCreateActive(category);

        expect(category.create_active).toBe(true);
    });

});

Upvotes: 2

user2847643
user2847643

Reputation: 2935

Like it says in the last listing toggleCreateActive is a function on the $scope. You cannot reference it as BoardController.toggleCreateActive. Instead make the scope var available for tests (move the declaration out of beforeEach) and call scope.toggleCreateActive().

Upvotes: 3

Related Questions