danwellman
danwellman

Reputation: 9253

Unit testing Angular directive click handler

I've got a directive that adds a click handler to an element:

module.directive('toggleSection', ['$timeout', function ($timeout) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.bind('click', function (event) {
                scope.$apply(function () {
                    var scopeProp = 'show' + attrs.toggleSection;

                    event.preventDefault();
                    event.stopPropagation();

                    scope[scopeProp] = !scope[scopeProp];

                    return false;
                });

            });
        }
    };
}]);

When the element is clicked, it toggles another property on the scope, which another element is bound to with ng-show. It's working as it should in the app.

I've added the following test for the directive:

(function () {
    'use strict';

    // get the app module from Angular
    beforeEach(module('app'));

    describe('myCtrl', function () {

        var $scope, $rootScope;

        beforeEach(inject(function ($controller, _$rootScope_) {
            $scope = {};
            $controller('myCtrl', { $scope: $scope });
            $rootScope = _$rootScope_;
        }));

        describe('the toggleSection directive', function () {

            var testElement;

            beforeEach(function () {
                testElement = $compile('<a toggle-section="Test" href="#">Collapse section</a>')($rootScope);
                $rootScope.$digest();
            });

            it('inverts the value of the specified scope property', function () {
                $scope.showTest = false;
                testElement.click();

                expect($scope.showTest).toEqual(true);
            });

        });
    });

In the real code there are properties like $scope.showSection1 = false and by adding console logs in the directive I can see the properties before and after clicking the bound element and they have the expected values (e.g. the property starts as false and after you click the toggle element once it changes to true).

However, the test always fails with 'Expected false to equal true'. I think it's to do with the $apply method, because none of the show properties seem to exist on the scope when I run the test.

Other tests I have (even in the same spec file), which don't use the directive can see properties on the scope just fine.

What am I doing wrong?

Upvotes: 0

Views: 1344

Answers (1)

Diana R
Diana R

Reputation: 1174

There are a few things to be changed in your test:

1 - scope creation should be changed from $scope = {} into $scope = $rootScope.$new();

2 - the directive should be compiled not into rootScope, but into scope

3 - the directive should first be created via angularjs.element and then compiled:

element = angular.element('<my-directive/>');
compile(element)(scope);
scope.$digest(); 

Upvotes: 3

Related Questions