Search code examples
angularjsangularjs-directiveangular-test

Test child transcended directive interaction with parent directive


I want to test an interaction between child and parent directive: My example :

app.directive('foo', function() {
  return {
    restrict: 'AE',
    template: '<div><div ng-transclude></div></div>', 
    transclude: true,
    controller: function($scope) {
      this.add = function(x, y) {
        return x + y;
      }
  }
};
});

app.directive('bar', function() {
  return {
    restrict: 'AE',
    require: '^foo',
    template: '<div></div>', 
    replace: true,
    link: function(scope, element, attrs, foo) {

      console.log('link directive bar')
      scope.callFoo = function(x, y) {
        scope.sum = foo.add(x, y);
      }
    }
  };
});

I want to test an interaction between boo and test, I do not want to mock child directive (boo) here is my test:

it('ensures callFoo does whatever it is supposed to', function() {
  // Arrange
  var element = $compile('<div foo><bar></bar></div>')($scope);

  var ele = element.find('bar')
  var barScope = element.find('bar').scope();

  console.log('parent element :',element)
  console.log('child element :',ele)


  // Act Undefined :(
  barScope.callFoo(1, 2);

  // Assert
  expect(barScope.sum).toBe(3);
});

full example: http://plnkr.co/edit/vYNFwpkbbHi4lsgwJkA9?p=preview


Solution

  • Your directives are already compiled, and since you have replace: true on the bar directive you'd no longer find bar in the DOM. You can see this by looking at element.html(), which would show something like this in your case:

    <div><div ng-transclude=""><div class="ng-scope"></div></div></div>
    

    If you remove replace: true your test would work.

    Otherwise, when jQuery is not loaded, jqLite is limited and its find method can only search tag names. So I tried to find your scope quickly like this:

    var barScope = element.find("div").eq(2).scope()
    

    Do you have jQuery loaded in your app? If so, you could load it in your test too, and then add some more info to the bar element like:

    var element = $compile('<div foo><bar id="bar"></bar></div>')($scope);
    

    Then you could find it like:

    var barScope = element.find('#bar').scope();