Search code examples
angularjsunit-testingcompilationcontrollerng-controller

How to test controller separately?


I have a controller for changing some DOM from different places.

The controller is:

angular.module('myModule').controller('myController', myController);

function myController() {
    this.addSomeClass = function() {
        $('#idOfSomeElement').addClass('someClass');
    };
}

And It is used like this. Inside different components and html.

<div id="idOfSomeElement"></div>
.
.
.
<some-angular-component-here>
    <div ng-controller="myController as ctrl">
        <div ng-click="ctrl.addSomeClass()"></div>
    </div>
</some-angular-component-here>
.
.
.
<using-in-onother-place>
    <div ng-controller="myController as ctrl">
        <div ng-click="ctrl.addSomeClass()"></div>
    </div>
</using-in-onother-place>

I try to test it like this, but I have undefined ctrl.

describe('Controller test', function () {
    'use strict';

    var ctrl,
        element;

    beforeEach(inject(function ($rootScope, $compile) {
        var scope = $rootScope.$new();
        angular.element('<div id="idOfSomeElement"></div>' +
                        '<div ng-controller="myController as ctrl">' +
                            '<div id="button" ng-click="ctrl.addSomeClass()"></div>' +
                        '</div>');

        element = $compile(element)(scope);
        scope.$apply();

        // how to get controller here with linked to html?
        ctrl = $controller('myController');
        ctrl = element.controller('myController');

    }));

    it('should add some class', function () {

        var button = $(element).find('#button')[0];
        $(button).trigger('click');

        var someElement = $(element).find('#idOfSomeElement')[0];
        expect(someElement).toHaveSomeClass();
    });
});

How to correct test this kind of controller? And I know that manipulate DOM inside controller it is bad thing but I need to unit test it.

Thanks


Solution

  • I think you forgot to assign the return value of angular.element to your element property...

    element = angular.element(....
    

    complete beforeEach:

    beforeEach(inject(function ($rootScope, $compile) {
        var scope = $rootScope.$new();
        element = angular.element('<div id="idOfSomeElement"></div>' +
                        '<div ng-controller="myController as ctrl">' +
                            '<div id="button" ng-click="ctrl.addSomeClass()"></div>' +
                        '</div>');
    
        element = $compile(element)(scope);
        scope.$apply();
    
        // how to get controller here with linked to html?
        ctrl = $controller('myController');
        ctrl = element.controller('myController');
    
    }));