gpt4 book ai didi

angularjs - 使用包含 ng-if 的模板对 AngularJS 指令进行单元测试

转载 作者:行者123 更新时间:2023-12-01 08:53:25 25 4
gpt4 key购买 nike

我正在尝试测试下一个 Angular 指令。它监听 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 中?

最佳答案

嗯,这就是我找到的解决方案。

需要注意两点:

  1. 指令将 replace 设置为 true .
  2. 模板有一个 ng-if 指令。

会发生这样的事情:

在测试中,指令编译时:

element = $compile('<sm-progress></sm-progress>')(scope);

<sm-progress></sm-progress>替换为:

<div class="in-progress" ng-if="isRouteLoading">
<span>.</span><span>.</span><span>.</span>
<div/>

同时,ng-if 为 false,所以最终渲染的代码只是一个注释。这就是 ng-if 的自然运作方式。

<!-- ngIf: isRouteLoading -->

$stateChangeStart 被触发时,scope.isRouteLoading 转到 true ,这使得 ng-if 将模板重新插入到 DOM。但在那一点 element 等于:

<!-- ngIf: isRouteLoading -->

不可能在里面找到指令模板。

// THE TEST FAILS
var progressEl = angular.element(element).find('in-progress');
expect(progressEl.length).toBeGreaterThan(0);

解决方案是将 html 文本包装在 div 或任何其他元素中。所以 ng-if 将在其中运行,我们可以检查接下来会发生什么。

it('scope.isRouteLoading should be false on start', function() {

// wrap sm-progress with a div tag
element = $compile('<div><sm-progress></sm-progress></div>')(scope);
scope.$digest();

expect(scope.isRouteLoading).toBe(false);

// In this point element compiles to:
// <div class="ng-scope"><!-- ngIf: isRouteLoading --></div>

$rootScope.$emit('$stateChangeStart');
expect(scope.isRouteLoading).toBe(true);
scope.$digest();

// Now element compiles to:
// <div class="ng-scope">
// <!-- ngIf: isRouteLoading -->
// <div class="sm-progress ng-scope" ng-if="isRouteLoading">
// <span>.</span><span>.</span><span>.</span>
// </div>
// <!-- end ngIf: isRouteLoading -->
// </div>

// Now the test pass.
var progressEl = angular.element(element).find('.in-progress');
expect(progressEl.length).toBeGreaterThan(0); //element is present

});

带有代码的 jsfiddle.net http://jsfiddle.net/fwxgyjwc/13/

我希望我已经解释得足够好。我的英语不是很好。

关于angularjs - 使用包含 ng-if 的模板对 AngularJS 指令进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34848102/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com