Ryan Duffing
Ryan Duffing

Reputation: 674

Unit testing directive's controller

I am struggling to get the controller from within a directive for unit testing. Here is my angular app:

angular.module('test-app', [])

    .controller('loadingCtr', ['$scope', function ($scope) {

    }])

    .directive('loading', function() {
        return {
            restrict: 'E',
            controller: 'loadingCtr'
       };
    });

Here is my unit test code:

describe('loading', function () {

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

        var fooElement = $compile('<loading></loading>')($rootScope);
        var fooController = fooElement.controller('loading');

        $rootScope.$digest();
        console.log(fooController);
    })); 

    describe('loading: testing loading directive', function() {
        it('should create loading directive', function() {
        });
    });
});

Here is a plnkr to mess around with: http://plnkr.co/edit/38cc5HQFgeHDhnC8OMo8?p=info

fooController always returns as undefined. I've tried using the following examples I've found online, but I always get the same results:

Unit testing a directive that defines a controller in AngularJS

http://daginge.com/technology/2014/03/03/testing-angular-directive-controllers-with-jasmine-and-karma/

Is there something obvious here that I am missing?

Upvotes: 2

Views: 3015

Answers (1)

PSL
PSL

Reputation: 123739

Only issue i can see is that you are not loading the module test-app in your fixture, which means that the compiled html code does not really compile the directive loading since it is not available in the injector. So try loading the module in the beforeEach block. Loading the module ensures that directives, controllers, services etc registered under the module is available in the injector otherwise it will just use the module as ng which does not know anything about the loading directive.

i.e

describe('loading', function () {
   var fooController;

    //Load the module 
    beforeEach(module('test-app'));

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

        var fooElement = $compile('<loading></loading>')($rootScope);
        fooController = fooElement.controller('loading');

        $rootScope.$digest();
        console.log(fooController);
    })); 

    describe('loading: testing loading directive', function() {
        it('should create loading directive', function() {
          expect(fooController).toBeDefined();
        });
    });
});

Demo

Also note that if you are registering the controller with .controller you can directly get the controller instance by $controller(ctrlName) construct. If you are using controllerAs syntax with bindToController:true in your directive then you can get it from the scope with the property name same as the alias as well.

Upvotes: 1

Related Questions