lundi 26 octobre 2015

Define a mock-directive in angular tests or unregister a directive

I'm testing an angular directive (i.e. top-level-element) which includes other directive via ng-include. And I want to test that my directive includes any template passed to ng-include and directives inside this template are compiled, run and so on. I understand that this is kind of testing the angular itself, but top-level-element is partly rendered not by the angular but with _.template due to performance reasons. So I want to be sure that ng-include isn't broken by this custom rendered part.

Currently I create new directive in my module, but this pollutes the module. I'd like to either create a mock directive or at least have an ability to unregister the directive I create in test. Does anybody has any ideas on how to do it?

Roughly the test looks like following:

describe('top level directive', function() {
    var mockDirective;
    var mockDirectiveName;
    var $templateCache;
    var $compile;
    var $scope;
    var element;

    beforeEach(function() {
        mockDirectiveName = 'includedDirective';
        mockDirective = {
           restrict: 'E',
           controller: jasmine.createSpy('mockDirective.controller'),
           template: '<p>some markup</p>',
           link: jasmine.createSpy('mockDirective.link')
        };

        var topLevelDirectiveModule = angular.module('topLevelDirectiveModule');
        // checking whether mockDirective has already been defined to avoid double definition
        var isTopLevelDirectiveDefined = topLevelDirectiveModule._invokeQueue.some(function(item) {
          return item[2][0] === mockDirectiveName;
        });     
        if (!isTopLevelDirectiveDefined) {
          /** I don't like polluting real module with test directive, but I couldn't find any way to register mock directive
              or unregister this one after tests */
          topLevelDirectiveModule.directive(mockDirectiveName, function() {
            return mockDirective;
          });
        }   

        inject(function($injector) {
            $compile = $injector.get('$compile');
            $scope = $injector.get('$rootScope').$new();
            $templateCache = $injector.get('$templateCache');
        });

        $templateCache.put('some/included.html', '<included-directive></included-directive>');

        element = $compile('<top-level-directive></top-level-directive>')($scope);
        $scope.$digest();
    });

    it('should show html', function() {
      expect(element.html()).toContain(mockDirective.template);
    });

    it('should run directive\'s controller', function() {
      expect(mockDirective.controller).toHaveBeenCalled();
    });

    it('should run directive\'s link', function() {
      expect(mockDirective.link).toHaveBeenCalled();
    }); 
});

And directive:

angular.module('topLevelDirectiveModule').directive('topLevelDirective', function() {
    return {
        template: '<div class="contents_of_this_are_rendered_by_lodash"></div>' + 
                  '<ng-include src="some/included.html"></ng-include>',
        restrict: 'E',
        controller: function() { /* some real controller to be here */},
        link: funciton($scope, elem, attrs, controllers) {
            var tpl = _.template('some template');
            elem.find('.contents_of_this_are_rendered_by_lodash').html(tpl());
        }
    };
});

Aucun commentaire:

Enregistrer un commentaire