eth*_*far 8 unit-testing mocking jasmine angularjs angularjs-directive
我正在写两个包含ui-bootstrap的tabset和tab指令的指令.
为了将我的指令的内容传递给包装指令,我在两个指令中使用了转换.
这很有效,唯一的问题是我没有编写检查它的测试.我的测试使用替换指令作为包装指令的模拟,我在每次测试之前使用$ compileProvider替换它.
测试代码看起来像这样:
beforeEach(module('myModule', function($compileProvider) {
// Mock the internally used 'tab' which is a third party and should not be tested here
$compileProvider.directive('tab', function() {
// Provide a directive with a high priority and 'terminal' set to true, makes sure that
// the mock directive will get executed, and that the real directive will not
var mock = {
priority: 100,
terminal: true,
restrict: 'EAC',
replace: true,
transclude: true,
template: '<div class="mock" ng-transclude></div>'
};
return mock;
});
}));
beforeEach(function() {
inject(function(_$compile_, _$rootScope_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
});
});
beforeEach(function() {
$scope = $rootScope.$new();
});
afterEach(function() {
$scope.$destroy();
});
it('Places the enclosed html inside the tab body', function() {
element = $compile("<div><my-tab>test paragraph</my-tab></div>")($scope);
$scope.$digest();
console.log("element.html() = ", element.html());
expect(element.text().trim()).toEqual("test paragraph");
});
Run Code Online (Sandbox Code Playgroud)
我的指令的模板看起来像这样:
<div><tab><div ng-transclude></div></tab></div>
Run Code Online (Sandbox Code Playgroud)
指令模块看起来像这样:
angular.module('myModule', ['ui.bootstrap'])
.directive('myTab', function() {
return {
restrict: 'E',
replace: true,
transclude: true,
templateUrl: 'templates/my-tab.tpl.html',
scope: {
}
};
});
Run Code Online (Sandbox Code Playgroud)
打印到控制台的结果如下:
LOG: 'element.html() = ', '<div class="ng-isolate-scope" id=""><div id="" heading="" class="mock"><ng-transclude></ng-transclude></div></div>'
Run Code Online (Sandbox Code Playgroud)
关于为什么不进行转换的任何想法(同样,它在测试之外工作得很好)?
我已经转移到其他的东西和指令,并再次遇到这个问题,但现在更重要的是,原因是,我放在父指令中的指令需要父控制器在其链接函数中.
我已经对此做了更多的研究,结果发现由于某种原因,编译mock指令不会创建被转换内容的实例.
我知道的原因是,我在两个指令(模拟和转换的指令)中都有一个打印输出,即编译,预链接,后链接和控制器构造函数,我看到了只有打印输出来自mock指令.
现在,这是非常有趣的部分:我已经尝试在mock指令的link函数中使用transclude函数来"强制"转换指令的编译,这是有效的!(另一个证据表明它没有隐含地发生).
你问的问题在哪里?嗯,它仍然无法正常工作.这一次,因为transcluded指令的链接功能失败,因为它找不到mock指令的控制器.什么 ?!
这是代码:
码
var mod = angular.module('MyModule', []);
mod.directive('parent', function() {
return {
restrict: 'E',
replace: true,
template: '<div class="parent">...</div>',
controller: function() {
this.foo = function() { ... };
}
};
});
mod.directive('child', function() {
return {
restrict: 'E',
require: '^parent',
link: function(scope, element, attrs, parentCtrl) {
parentCtrl.foo();
}
};
});
Run Code Online (Sandbox Code Playgroud)
测试
describe('child directive', function() {
beforeEach(module('MyModule', function($compileProvider) {
$compileProvider.directive('parent', function() {
return {
priority: 100,
terminal: true,
restrict: 'E',
replace: true,
transclude: true,
template: '<div class="mock"><ng-transclude></ng-transclude></div>',
controller: function() {
this.foo = jasmine.createSpy();
},
link: function(scope, element, attrs, ctrls, transcludeFn) {
transcludeFn();
}
};
});
}));
});
Run Code Online (Sandbox Code Playgroud)
此测试失败,并显示错误消息,例如:
错误:[$ compile:ctreq]无法找到指令'child'所需的控制器'parent'!
任何想法,想法和建议都将受到高度赞赏.
好吧,可能是SO史上最短的赏金......
问题是与terminal: true和priority: 100模拟指令的性质.我的印象(从我在线阅读的关于如何模拟指令的文章),这些属性导致编译器停止编译具有相同名称的指令,并优先处理要首先计算的mock指令.
我显然是错的.看着这个和这个,很明显:
问题是,这会导致所有其他处理停止,包括ng-transclude指令,其默认优先级为0.
但是,删除这些属性会导致所有地狱崩溃,因为这两个指令都已经注册,等等(我不会给你带来所有的血腥细节).为了能够删除这些属性,这两个指令应该驻留在不同的模块中,并且它们之间不应该存在依赖关系.简而言之,在测试child指令时,唯一指定的指令parent应该是mock指令.
为了支持现实生活,我向系统引入了三个模块:
child指令的模块(无依赖关系)parent指令的模块(无依赖关系)child和parent模块的模块,这是您需要在代码中作为依赖项添加的唯一模块这就是它.我希望它可以帮助其他任何遇到此类问题的人.
| 归档时间: |
|
| 查看次数: |
1176 次 |
| 最近记录: |