如何在angularjs中测试是否加载指令

时间:2016-12-15 07:08:07

标签: javascript angularjs unit-testing testing angular-directive

我写了一个指令,它在参数中取指令名,并将该指令动态地加载为fallow:

.directive("loadDirective", function($compile, $timeout) {
        return {
            restrict: 'E',
            scope: {
                Dtype: '=type',
                subType: '@',
                data: "=data"
            },
            link: function(scope, element) {
                scope.$watch('Dtype', function() {
                    $timeout(function() {
                        var generatedTemplate = '<div ' + scope.Dtype + (scope.subType ? '-' + scope.subType + '-directive' : '-directive') + ' data="data" >dd</div>';
                        element.empty().append($compile(generatedTemplate)(scope));
                    })
                })
            },
        };
    })

这是我将动态加载它的指令之一

.directive("dailyIntervalDirective", function() {
        return {
            scope: {
                data: '='
            },
            restrict: 'A',
            templateUrl: '/flat-ui/tpls/daily-interval.html'
        };
    })

现在我正在尝试为loadDiretive编写测试用例以测试它是否加载指令,如下所示:

describe("loadDirective directive", function() {
    var elm, scope;
    beforeEach(module('guideApp.directives'));
    beforeEach(module('/flat-ui/tpls/daily-interval.html'));
    beforeEach(angular.mock.inject(function($rootScope, $compile) {
        scope = $rootScope;
        elm = angular.element('<load-directive type="directive" sub-type="interval" data="schedulerData"></load-directive>');
        compile = $compile;
        compile(elm)(scope);
        scope.schedulerData = {
            interval: 1,
        }
        scope.$digest();
    }));
    it("should be able to load daily directive", function() {
        scope.directive = "daily";
        var intervaldirective = elm.find('div[daily-interval-directive]');
        expect(intervaldirective.length).toEqual(1);
    });
   });

对我来说效果不好。我试图记录榆树,但它没有加载dailyInterevalDirective。

2 个答案:

答案 0 :(得分:1)

您的 dailyIntervalDirective 似乎有 templateUrl

现在,如果指令有效,那么在测试中,您可以使用 GET 调用 "/flat-ui/tpls/daily-interval.html" httpBackend 服务。因为编译 dailyIntervalDirective 指令后应立即加载该模板。希望能帮助到你。 :)

[编辑]
此外,我怀疑elm.find('div[daily-interval-directive]');是否有效,正如angular docs.中提到 find() - Limited to lookups by tag name

根据要求,请在下面找到示例代码段:

// -----in your spec file----  
describe("loadDirective directive", function() {
var elm, scope,$httpBackend;
beforeEach(module('guideApp.directives'));
beforeEach(angular.mock.inject(function($rootScope, $compile,$httpBackend) {
    scope = $rootScope;
    $httpBackend= $httpBackend;
    $httpBackend.whenGET('/flat-ui/tpls/daily-interval.html').respond(200, 'any response you can send here, even a blank string, as it is just to test ');
    elm = angular.element('<load-directive type="directive" sub-type="interval" data="schedulerData"></load-directive>');
    compile = $compile;
    compile(elm)(scope);
    scope.schedulerData = {
        interval: 1,
    }
    scope.$digest();
}));
it("should try to load daily directive's template", function() {
    scope.directive = "daily";
    $httpBackend.expectGET('/flat-ui/tpls/daily-interval.html');
    $httpBackend.flush();
});
});

如果此测试用例应该通过,则表示该指令已加载。

答案 1 :(得分:1)

问题分为两部分。第一个问题是指令定义对象中的templateUrl。正如@r_goyal here所回答的那样,每当通过URL加载模板时,都会通过GET调用加载。因此,您需要使用httpBackend来模拟它。

第二部分是$timeout的用法。 $ timeout异步执行,但测试同步执行。这是您测试失败的原因。要在$timeout中测试代码,我们使用$timeout service found in angular.mock module进行模拟。我们需要在模拟$timeout.flush服务上使用$timeout方法来强制原始$timeout中的代码同步执行。这是一个完全更正的例子:

describe("loadDirective directive", function() {
    var elm, scope, timeout, httpBackend;
    beforeEach(module('guideApp.directives'));
    beforeEach(module('/flat-ui/tpls/daily-interval.html'));
    beforeEach(angular.mock.inject(function($rootScope, $compile, $timeout, $httpBackend) {
        scope = $rootScope;
        timeout = $timeout;
        httpBackend = $httpBackend;

        elm = angular.element('<load-directive type="directive" sub-type="interval" data="schedulerData"></load-directive>');
        compile = $compile;
        compile(elm)(scope);
        scope.schedulerData = {
            interval: 1,
        }
        scope.$digest();
    }));
    it("should be able to load daily directive", function() {
        scope.directive = "daily";
        httpBackend.when('GET','/flat-ui/tpls/daily-interval.html').respond("<div> Any mock template or the original template loaded as a fixture </div>");

        scope.$apply();
        timeout.flush();
        httpBackend.flush();
        var intervaldirective = elm.find('div[daily-interval-directive]');
        expect(intervaldirective.length).toEqual(1);
    });
   });

有几点需要注意:

  • 这里我们将scope.$apply()称为加载指令的代码 动态地在 watch 中。即使您设置了Dtype变量 范围为新值,监视功能将不会执行 直到启动摘要周期

  • 然后,我们致电timeout.flush()强制$timeout中的代码转到 同步执行

You can read more about testing $timeout here

希望这有帮助