0

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?

10
  • 2
    You should compile your directive in test agains scope not rootScope. Try that and let me know if it solves your issue. Also, not sure if this will help, but I create my directive by first creating angular.element:element = angular.element('<my-directive/>');compile(element)(scope);scope.$digest();
    – Diana R
    CommentedSep 14, 2015 at 12:53
  • Hi Diana, I tried this (this was the only thing I changed, I left $digest() being called on $rootScope), but now the test has an error: 'undefined' is not a function (evaluating 'scope.$apply') - it's tripping up on the use of '$apply()' in the directive itself..?CommentedSep 14, 2015 at 12:58
  • 1
    Well if you compile it against rootScope, it will be in the rootScope.$apply. That is why I am saying you have to compile it against scope, not rootScope.
    – Diana R
    CommentedSep 14, 2015 at 13:01
  • 1
    Ah ok, this is because your scope is not created properly. It should be created in before each not just $scope = {} but $scope = $rootScope.$new();
    – Diana R
    CommentedSep 14, 2015 at 13:08
  • 1
    Ok thanks for the explanation!CommentedApr 13, 2016 at 11:22

1 Answer 1

3

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(); 
0

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.