【发布时间】:2015-05-06 11:11:55
【问题描述】:
我正在编写两个指令来包装 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");
});
我的指令模板如下所示:
<div><tab><div ng-transclude></div></tab></div>
指令模块看起来像这样:
angular.module('myModule', ['ui.bootstrap'])
.directive('myTab', function() {
return {
restrict: 'E',
replace: true,
transclude: true,
templateUrl: 'templates/my-tab.tpl.html',
scope: {
}
};
});
打印到控制台的结果是这样的:
LOG: 'element.html() = ', '<div class="ng-isolate-scope" id=""><div id="" heading="" class="mock"><ng-transclude></ng-transclude></div></div>'
关于为什么不发生嵌入的任何想法(同样,它在测试之外也可以正常工作)?
更新
我已经转向其他事情和指令,并再次遇到这个问题,但现在更重要的是,我放置在父指令中的指令在其链接功能中需要父控制器.
我对此进行了更多研究,结果发现由于某种原因,编译 mock 指令不会创建嵌入内容的实例。
我知道这一点的原因是,我在两个指令(模拟和嵌入指令)的每个钩子中都放置了一个打印输出,即编译、预链接、后链接和控制器构造函数,我看到只有打印输出来自模拟指令。
现在,真正有趣的部分来了:我尝试在模拟指令的链接函数中使用 transclude 函数来“强制”编译 transcluded 指令,它奏效了! (另一个证明它不是隐式发生的)。
你问的问题在哪里?好吧,它仍然不起作用。这一次,由于 transcluded 指令的链接功能失败,因为它没有找到模拟指令的控制器。什么?!
代码如下:
代码
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();
}
};
});
测试
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();
}
};
});
}));
});
此测试失败并显示如下错误消息:
错误:[$compile:ctreq] 控制器“父级”,指令要求 '孩子',找不到!
任何想法、想法、建议都将受到高度赞赏。
【问题讨论】:
-
您可以尝试在 URL 前添加正斜杠,如下所示:
templateUrl: '/templates/my-tab.tpl.html' -
这绝对不是问题,因为找到了模板(否则模拟不会在控制台输出中可见,指令模板就是在那个 HTML 中植入模拟的那个)。开头没有斜线的原因是该文件夹相对于 JS 文件所在的位置。无论如何,这无关紧要。
标签: angularjs unit-testing angularjs-directive mocking jasmine