Testing ui-grid wrapped in another directive

Problem

I'm trying to create a directive that will allow me to set certain configurations to ui-grid as well as to add some functionality to it. I got something basic working, but the problem is that the jasmine test is giving me a hard time.

The JS code looks like this:

angular.module('myGridDirective', ['ui.grid'])

.directive('myGrid', function() {
    return {
        restrict: 'E',
        replace: true,
        templateUrl: 'templates/my-grid.html'
    };
});

The template looks like this:

<div><div id="test-id" class="gridStyle" ui-grid="gridOptions"></div></div>

And the test looks like this:

describe('my grid directive', function() {
    var $compile, 
        $rootScope;

    beforeEach(module('myGridDirective'));

    beforeEach(module('templates/my-grid.html'));

    beforeEach(function() {
        inject(function(_$compile_, _$rootScope_) {
            $compile = _$compile_;
            $rootScope = _$rootScope_;
        });
    });

    it('Replaces the element with an ui-grid directive element', function() {
        var element = $compile("<my-grid></my-grid>")($rootScope);

        $rootScope.$digest();

        expect(element.html()).toEqual('<div id="test-id" class="gridStyle" ui-grid="gridOptions"></div>');
    });
});

The problem is that, while the directive is working (i.e. using <my-grid></my-grid> anywhere in my html file works), the test is failing. I get the error message:

TypeError: $scope.uiGrid is undefined in .../angular-ui-grid/ui-grid.js (line 2879)

The relevant line in ui-grid.js is (the first line is 2879):

if (angular.isString($scope.uiGrid.data)) {
        dataWatchCollectionDereg = $scope.$parent.$watchCollection($scope.uiGrid.data, dataWatchFunction);
      }
      else {
        dataWatchCollectionDereg = $scope.$parent.$watchCollection(function() { return $scope.uiGrid.data; }, dataWatchFunction);
      }

The thing is, if I replace the ['ui.grid'] array in the directive module creation with an empty array, the test passes. The only problem, is that if I do that, I'll have to include 'ui.grid' anywhere the directive is used otherwise the directive stops working, which is something I cannot do.

I already tried transcluding, but that didn't seem to help, not to mention that the directive itself works, so it doesn't seem logical to have to do that just for the test.

Any thoughts ?

Problem courtesy of: eitanfar

Solution

Ok, I figured out the solution.

At first found one way to solve this, which is:

  • Initialize the gridOptions variable with some data so that the ui-grid will get constructed

However, once I got that to work, I tried to add 'expect' statements, when it hit me that now I have a lot of 3rd party html to test, which is not what I want. The final solution was to decide to mock the inner directive (which should be tested elsewhere), and to use the mock's html instead.

Since ngMock does not support directives, I found this great article explaining how to mock directives using $compileProvider, which solved my problem altogether.

Solution courtesy of: eitanfar

Discussion

There is currently no discussion for this recipe.

This recipe can be found in it's original form on Stack Over Flow.