0

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

Taras Kravets
  • 1,443
  • 4
  • 14
  • 15
  • DOM fixtures in tests are detached from the document, so `$('#idOfSomeElement')` selector won't reach the fixture. Your best bet is to mock `$(...)` (most likely can be done by stubbing jQuery `init` method, like it is shown [here](http://stackoverflow.com/a/36356692/3731501)) and `addClass` method and spy on their calls. This is one of the reasons why mixing jQuery with Angular is bad thing. And yes, this shouldn't be done in controller. – Estus Flask Sep 22 '16 at 17:49

1 Answers1

0

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');

}));
Thibs
  • 8,058
  • 13
  • 54
  • 85