1

I am trying to write a unit test for the toggleDetails function defined inside the following AngularJS directive:

angular.module('hadoopApp.cluster.cluster-directive', [])

.directive('cluster', [function() {
  return {
    templateUrl:'components/cluster/cluster.html',
    restrict: 'E',
    replace: true,
    scope: {
      clusterData: '=',
      showDetails: '='
    },
    link: function(scope, element, attrs) {
      scope.toggleDetails = function() {
        console.log('Test');
        scope.showDetails = !scope.showDetails;
      };
    },
    // Default options 
    compile: function(tElement, tAttrs){
      if (!tAttrs.showDetails) { tAttrs.showDetails = 'false'; }
    }
  };

}]);

And this is the unit test:

'use strict';   
describe('hadoopApp.cluster module', function() {
  // Given
  beforeEach(module('hadoopApp.cluster.cluster-directive'));    

  var compile, mockBackend, rootScope;  
  beforeEach(inject(function($compile, $httpBackend, $rootScope) {
    compile = $compile;
    mockBackend = $httpBackend;
    rootScope = $rootScope;
  }));

  var dummyCluster;
  beforeEach(function() {
    dummyCluster = {
      id:"189",
      name:"hadoop-189",
      exitStatus:0
    };    
    mockBackend.expectGET('components/cluster/cluster.html').respond(
      '<div><div ng-bind="clusterData.name"></div></div>');
  });

  it('should toggle cluster details info', function() {
    var scope = rootScope.$new();
    scope.clusterData = dummyCluster;

    // When
    var element = compile('<cluster' +
      ' cluster-data="clusterData" />')(scope);
    scope.$digest();
    mockBackend.flush();

    // Then
    var compiledElementScope = element.isolateScope();
    expect(compiledElementScope.showDetails).toEqual(false);

    // When
    console.log(compiledElementScope);
    compiledElementScope.toggleDetails();

    // Then
    expect(compiledElementScope.showDetails).toEqual(true);
  });

  afterEach(function() {
    mockBackend.verifyNoOutstandingExpectation();
    mockBackend.verifyNoOutstandingRequest();
  });
});

The test fails when calling compiledElementScope.toggleDetails() because the toggleDetails function is undefined:

TypeError: undefined is not a function

Printing the content of the isolated scope inside compiledElementScope I can see that in fact the function is not included in the object.

So, it looks like the toggleDetails function is not included in the isolated scope but I don't know why.

1 Answer 1

1

If you use the compile function within a directive, the link function is ignored. You should return the function within the compile method:

        compile: function (tElement, tAttrs) {

            if (!tAttrs.showDetails) {
                tAttrs.showDetails = 'false';
            }
            return {
                post: function (scope, element, attrs) {
                    console.log('Test');
                    scope.toggleDetails = function () {
                        console.log('Test');
                        scope.showDetails = !scope.showDetails;
                    };
                }
            };
        }

Also, in order to make the test work, you should add:

    scope.showDetails = false;

And the binding to the directive (because you require two values):

    var element = compile('<cluster' +
        ' cluster-data="clusterData" show-details="showDetails" />')(scope);

Jsfiddle: http://jsfiddle.net/phu7sboz/

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! It works perfectly. What I do not understand why scope.showDetails = false is needed since it's default option should be false.
Because you are binding it as a two way binded variable, if it was a single way variable, it would have been fine
Thanks a lot! I have a deficient knowledge about how '=' actually works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.