我正在尝试测试下一个角度指令。它会收听 ui-route $ stateChange 事件以显示进度指示器。
angular.module('sm.components.progress', ['ui.router'])
.directive('smProgress', function($rootScope) {
return {
restrict: 'E',
replace: true,
template: '<div class="in-progress" ng-if="isRouteLoading">' +
'<span>.</span><span>.</span><span>.</span>' +
'<div/>',
controller: function($scope) {
$scope.isRouteLoading = false;
$rootScope.$on('$stateChangeStart',
function() {
$scope.isRouteLoading = true;
});
$rootScope.$on('$stateChangeSuccess',
function() {
$scope.isRouteLoading = false;
});
}
};
});
这是我的测试代码:
describe('smProgress', function() {
var $compile, $rootScope, element, scope;
beforeEach(module('sm.components.progress'));
beforeEach(inject(function(_$compile_, _$rootScope_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
scope = $rootScope.$new();
}));
afterEach(function() {
element.remove();
});
it('$rootScope.isRouteLoading should be false on start',
function() {
element = $compile('<sm-progress></sm-progress>')(scope);
scope.$digest();
expect(scope.isRouteLoading).toBe(false);
$rootScope.$emit('$stateChangeStart');
//The directive listen to the $stateChangeStart and
//scope.isRouteLoading become true as expected
expect(scope.isRouteLoading).toBe(true);
scope.$digest();
// checks if the template is rendered when ng-if evaluates true
// how?
}));
});
模板中的 ng-if 开始评估false
,因此该元素将从DOM中删除。当我手动发出$stateChangeStart
事件时,指令监听器工作,但我找不到DOM中的元素。
当 ng-if 再次评估为true
时,如何检查模板是否已添加到DOM?
答案 0 :(得分:9)
嗯,这是我找到的解决方案。
重要的是要注意两件事:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<p>
See <a href='http://stackoverflow.com/q/34818540/841108'>this SO question</a>
</p>
<h2> my menu </h2>
<p class='explaincl'>
First, try clicking the button, and do nothing more: the menu disappears in 10 sec. Then, try again, click the button, move the mouse inside the menu, it is still disappearing but I want it to stay!</p>
<button id='mybutton_id'>click me</button>
<div id='mymenudiv_id'>
Here
</div>
<p id='message_id'>
</p>
。这就是:
在测试中,编译指令时:
true
element = $compile('<sm-progress></sm-progress>')(scope);
替换为:
<sm-progress></sm-progress>
同时,ng-if为false,因此最终呈现的代码只是一个注释。这就是 ng-if 自然地工作的方式。
<div class="in-progress" ng-if="isRouteLoading">
<span>.</span><span>.</span><span>.</span>
<div/>
当触发 $ stateChangeStart 时, scope.isRouteLoading 转到<!-- ngIf: isRouteLoading -->
,这会使 ng-if 重新插入模板DOM。但在这一点上元素等于:
true
无法在其中找到指令模板。
<!-- ngIf: isRouteLoading -->
解决方案是将html文本包装在 div 或任何其他元素中。因此ng-if将在其中运行,我们可以检查当时发生的事情。
// THE TEST FAILS
var progressEl = angular.element(element).find('in-progress');
expect(progressEl.length).toBeGreaterThan(0);
jsfiddle.net,代码工作http://jsfiddle.net/fwxgyjwc/13/
我希望我已经解释得很好。我的英语不是很好。