【发布时间】:2014-08-07 19:34:17
【问题描述】:
我目前正在尝试使用 jasmine 测试 angular 指令。
下面是被测指令的简化示例:
angular.module('app', []).directive('testDirective', [
function() {
return {
restrict:'A',
scope: {
myAttr: '@'
},
link: function(scope, element, attrs) {
element.html(scope.myAttr);
scope.$watch('myAttr', function(n, o) {
if(n !== o) {
element.html(n);
}
});
}
};
}
]);
使用隔离范围,它将属性 data-my-attr 的值单向绑定到 myAttr 的范围值,然后观察 myAttr 的值是否有任何变化,此时它会更新显示的元素。
再一次,为了清晰起见,这段代码已经过大量修改,所以请原谅这个高度人为的例子。
测试是编译一个包含这个指令的元素,验证元素的初始html设置是否正确(是)然后改变属性的值并期望元素发生相应的变化(不是)。这是测试代码的简化版本。
it('fires myAttr watch', function() {
var body = angular.element('body');
var template = angular.element('<div id="testid" data-test-directive data-my-attr="initialValue"/>');
body.append([template]);
compile(template)(scope);
scope.$digest();
expect(angular.element('#testid').text()).toEqual('initialValue');
template.attr('data-my-attr', 'newValue');
scope.$digest();
expect(angular.element('#testid').text()).toEqual('newValue');
});
虽然该指令在生产中使用时按预期工作,但在测试中,更新属性的值似乎不会导致相应的范围值更新,从而导致手表永远不会触发。为什么作用域上的值没有更新,为什么这只发生在测试中?
这是一个演示问题的 plunkr http://plnkr.co/edit/MmS1X2zrPZyGSUIVUsDg?p=preview
有什么想法吗?
【问题讨论】:
-
在调用范围摘要之前更新值后需要添加
compile(template)(scope); -
我注意到这样做确实可以解决问题,但我想我不确定这是正确的解决方案还是碰巧有效的破解方法。我认为 $compile 是一次性交易,旨在识别指令并将它们适当地绑定到范围,这是否意味着每当我进入 html 并更改某些东西时,在幕后重新编译所有内容?此外,如果是这种情况,是什么触发了测试中没有发生的生产代码中的重新编译(在哪里可以正常工作)?
-
在这种情况下你的测试是错误的。在您的测试中,您正在修改元素的属性,该属性不会被摘要评估。你需要重新编译。是的,即使在应用程序中,如果您通过手动 DOM 操作在 html 中手动更改某些内容(例如:绑定模型、更改指令、在元素上动态添加指令),您也需要重新编译它。那么你是如何在你的生产代码中做到这一点的......
-
您是否在生产代码中这样做? plnkr.co/edit/BwDtXZRMtMWAcvMSL8vZ?p=preview您还需要发布您的实际代码..
-
啊,很好,你是对的。我没有注意到指令的实际用法是将其绑定到范围变量(正如您的 plunkr 建议的那样),这解释了为什么简单的摘要循环足以更新值。感谢您的帮助。
标签: javascript angularjs testing jasmine directive