scope.$watch 在 scope.$digest in karma 单元测试后没有被触发
scope.$watch does not get triggered after scope.$digest in karma unit test
我想测试这个指令:
.directive('mwIcon', function () {
return {
restrict: 'A',
scope: {
mwIcon: '@',
tooltip: '@',
placement: '@',
style: '@'
},
template: '<i ng-class="iconClasses" style="{{style}}" mw-tooltip="{{tooltip}}" placement="{{placement}}"></i>',
link: function (scope, el) {
el.addClass('mw-icon');
//set icon classes
scope.$watch('mwIcon', function (newVal) {
if (newVal) {
var isFontAwesome = angular.isArray(scope.mwIcon.match(/^fa-/)),
isRlnIcon = angular.isArray(scope.mwIcon.match(/rln-icon/));
if (isFontAwesome) {
scope.iconClasses = 'fa ' + scope.mwIcon;
} else if (isRlnIcon) {
scope.iconClasses = 'rln-icon ' + scope.mwIcon;
} else {
scope.iconClasses = 'glyphicon glyphicon-' + scope.mwIcon;
}
}
});
}
};
})
具体来说,当我更改 scope.mwIcon
时会发生什么。它也应该更改 <i>
元素的 class,因为 scope.mwIcon
有一个观察者,对吗?这是我的测试:
it('should change the class according to the new icon', function () {
var icon = '<span mw-icon="search"></span>';
var el = $compile(icon)(scope);
scope.$digest();
expect(el.children().hasClass("glyphicon")).toBe(true);
expect(el.children().hasClass("glyphicon-search")).toBe(true);
scope.mwIcon = "fa-star";
scope.$digest();
expect(el.children().hasClass("fa")).toBe(true);
expect(el.children().hasClass("fa-star")).toBe(true);
});
底部的两个断言 return 为假,即使我用 scope.$digest
触发了 scope.mwIcon
的更改。知道为什么我的 <i>
元素仍然有 classes "glyphicon glyphicon-search" 而不是 "fa fa-star" 吗?
您将 mwIcon 绑定到一个属性字符串(带有 @),因此随后设置 scope.mwIcon,将不会触发 $watch。您可以将其更改为双向绑定 (mwIcon: '=',) 或尝试改用 attr.$observe,将 attrs 作为第三个参数添加到 link 函数中,但我还没有尝试过最后一种方法。
问题在于该指令使用的是独立作用域。在隔离范围上设置新 mwIcon
时,测试有效。
it('should change the class according to the new icon', function () {
var icon = '<span mw-icon="search"></span>';
var el = $compile(icon)(scope);
var isolatedScope = el.isolateScope();
scope.$digest();
expect(el.children().hasClass("glyphicon")).toBe(true);
expect(el.children().hasClass("glyphicon-search")).toBe(true);
isolatedScope.mwIcon = "fa-star";
scope.$digest();
expect(el.children().hasClass("fa")).toBe(true);
expect(el.children().hasClass("fa-star")).toBe(true);
});
我想测试这个指令:
.directive('mwIcon', function () {
return {
restrict: 'A',
scope: {
mwIcon: '@',
tooltip: '@',
placement: '@',
style: '@'
},
template: '<i ng-class="iconClasses" style="{{style}}" mw-tooltip="{{tooltip}}" placement="{{placement}}"></i>',
link: function (scope, el) {
el.addClass('mw-icon');
//set icon classes
scope.$watch('mwIcon', function (newVal) {
if (newVal) {
var isFontAwesome = angular.isArray(scope.mwIcon.match(/^fa-/)),
isRlnIcon = angular.isArray(scope.mwIcon.match(/rln-icon/));
if (isFontAwesome) {
scope.iconClasses = 'fa ' + scope.mwIcon;
} else if (isRlnIcon) {
scope.iconClasses = 'rln-icon ' + scope.mwIcon;
} else {
scope.iconClasses = 'glyphicon glyphicon-' + scope.mwIcon;
}
}
});
}
};
})
具体来说,当我更改 scope.mwIcon
时会发生什么。它也应该更改 <i>
元素的 class,因为 scope.mwIcon
有一个观察者,对吗?这是我的测试:
it('should change the class according to the new icon', function () {
var icon = '<span mw-icon="search"></span>';
var el = $compile(icon)(scope);
scope.$digest();
expect(el.children().hasClass("glyphicon")).toBe(true);
expect(el.children().hasClass("glyphicon-search")).toBe(true);
scope.mwIcon = "fa-star";
scope.$digest();
expect(el.children().hasClass("fa")).toBe(true);
expect(el.children().hasClass("fa-star")).toBe(true);
});
底部的两个断言 return 为假,即使我用 scope.$digest
触发了 scope.mwIcon
的更改。知道为什么我的 <i>
元素仍然有 classes "glyphicon glyphicon-search" 而不是 "fa fa-star" 吗?
您将 mwIcon 绑定到一个属性字符串(带有 @),因此随后设置 scope.mwIcon,将不会触发 $watch。您可以将其更改为双向绑定 (mwIcon: '=',) 或尝试改用 attr.$observe,将 attrs 作为第三个参数添加到 link 函数中,但我还没有尝试过最后一种方法。
问题在于该指令使用的是独立作用域。在隔离范围上设置新 mwIcon
时,测试有效。
it('should change the class according to the new icon', function () {
var icon = '<span mw-icon="search"></span>';
var el = $compile(icon)(scope);
var isolatedScope = el.isolateScope();
scope.$digest();
expect(el.children().hasClass("glyphicon")).toBe(true);
expect(el.children().hasClass("glyphicon-search")).toBe(true);
isolatedScope.mwIcon = "fa-star";
scope.$digest();
expect(el.children().hasClass("fa")).toBe(true);
expect(el.children().hasClass("fa-star")).toBe(true);
});