2

I'm kinda new in AngularJS unit testing and I'm having some troubles to test a controller method that was written in a directive.

This is my directive.js

app.directive('formLogin', ['AuthService', function(AuthService){
    return {
        restrict: 'E',
        templateUrl: utils.baseUrl + 'partials/_home-form-login.html',
        replace: true,
        controller: function ($scope, $element, $http, $location) {
            $scope.visible = false;
            $scope.showForm = function () {
                $scope.visible = !$scope.visible;
            };
        }
    };
}]);

And here goes my unit-test.js

describe('formLogin ctrl', function () {
    var element, scope, compile;

    beforeEach(module('Application'));

    beforeEach(inject(function ($rootScope, $compile) {
        element = angular.element('<form-login></form-login>');
        scope = $rootScope.$new();
        compile = $compile(element)($scope);       
    }));

    it('Test', function() {
        expect(scope.visible).toBe(false);
    })
});

And by doing this the "scope.visible" come as undefined.

There are some way to take the $scope from my controller that assumes in "scope" variable the "visible" property and the "showForm" method?

3 Answers3

2

From this link it looks like you might need to do a scope.$digest();

smk
  • 5,340
  • 5
  • 27
  • 41
2

You appear to have a couple problems:

  1. compile = $compile(element)($scope); -- here, $scope is undefined. It should be compile = $compile(element)(scope);
  2. As mentioned by smk, you need to digest your scope to finish the directive creation process
    • This is especially important because you are using templateUrl. When you just use a locally-defined template, as Krzysztof does in his example, you can get by with skipping this step.

You will probably notice that when you add scope.$digest() you will get a different problem about an unexpected GET request. This is because Angular is trying to GET the templateUrl, and during testing all HTTP requests must be configured / expected manually. You might be tempted to inject $httpBackend and do something like $httpBackend.whenGet(/partials\//).respond('<div/>'); but you will end up with problems that way.

The better way to accomplish this is to inject the template $templateCache -- Karma has a pre-processor to do this for you, or you can do it manually. There have been other StackOverflow questions you can read about this, like this one.

I've modified your example to manually insert a simple template into the $templateCache as a simple example in this plunkr.

You should take a look into Karma's html2js pre-processor to see if it can do the job for you.

Community
  • 1
  • 1
bloveridge
  • 271
  • 2
  • 4
0

If your directive hasn't isolated scope, you can call methods from directive controller and test how it impacts to scope values.

describe('myApp', function () {
    var scope
      , element
    ;

    beforeEach(function () {
        module('myApp');
    });

    describe('Directive: formLogin', function () {
        beforeEach(inject(function ($rootScope, $compile) {
            scope = $rootScope.$new();
            element = angular.element('<form-login></form-login>');
            $compile(element)(scope);
        }));

        it('.showForm() – changes value of $scope.visible', function() {
            expect(scope.visible).toBe(false);
            scope.showForm();
            expect(scope.visible).toBe(true);
        });
    });
});

jsfiddle: http://jsfiddle.net/krzysztof_safjanowski/L2rBV/1/

Krzysztof Safjanowski
  • 7,292
  • 3
  • 35
  • 47