Snowy007
Snowy007

Reputation: 147

Testing Angular with parent controller method call

I'm trying to write unit-tests for an Angular application for the first time. Currently i'm having some problems running the tests. Running the application normally works fine, it doesn't give any errors. However, when running the tests using Karma and Jasmine i'm getting the following error:

TypeError: 'undefined' is not a function (evaluating '$scope.addActiveClassToMenuButton('menuButtonHome')')

I'm using the ui.router module. Not sure if that matters.

Parent controller

Parent controller contains the following method:

angular.module('testApp')
.controller('ParentCtrl', function ($scope, $resource) {

    $scope.addActiveClassToMenuButton = function(buttonId) {
        //Some code
    }

}

Child controller

Child controller calls the parents method like this:

angular.module('testApp')
.controller('ChildCtrl', function ($scope, $resource) {

    $scope.addActiveClassToMenuButton('menuButtonHome');

}

Child controller test file

The test file that fails:

describe('Child controller tests. ', function () {
    beforeEach(module('testApp'));

    var ChildCtrl, scope;

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

    it('simple false test', function () {
      expect(false).toBe(false);
    });
});

Even though i'm not using the scope in the test yet, all tests fail because the code can't find the parents method.

Solution

Changing the test file to this worked:

describe('Child controller tests. ', function () {
  beforeEach(module('testApp'));

  var controller, scope, parentScope, childScope;

  beforeEach(inject(function ($controller, $rootScope, $compile) {
    scope = $rootScope.$new();
    var el = angular.element('<div ng-controller="ParentCtrl"><div ng-controller="ChildCtrl"></div></div>');
    $compile(el)(scope);

    parentScope = el.scope();
    childScope = el.children().scope();
  }));

  it('simple false test', function () {
    expect(false).toBe(false);
  });

});

Upvotes: 1

Views: 2026

Answers (1)

Vinay K
Vinay K

Reputation: 5572

Try this..

describe('Child controller tests. ', function () {
    beforeEach(module('testApp'));

    var ChildCtrl, scope;

    beforeEach(inject(function ($controller, $rootScope, $compile) {
      scope = $rootScope.$new();
      var el = angular.element('<div ng-controller="ParentCtrl"><div ng-controller="ChildCtrl"></div></div>');

      $compile(el)(scope);

      // to access parent controller.
      var parentScope = el.scope();
      var childScope = el.children().scope();

      // now you should be able to access from parent and child scopes.
    }));

    it('simple false test', function () {
      expect(false).toBe(false);
    });
});

This will instantiate ParentCtrl first and then extend the scope of it with the ChildCtrl's scope.

In the example that you have given only ChildCtrl is instantiated ParentCtrl is not instantiated.

Upvotes: 4

Related Questions