angularjs – 在指令测试中模拟所需的控制器
|
我正在努力弄清楚如何模仿我所写的指令所需的控制器,这是另一个人的孩子.
首先让我分享我的指令: 家长 angular
.module('app.components')
.directive('myTable',myTable);
function myTable() {
var myTable = {
restrict: 'E',transclude: {
actions: 'actionsContainer',table: 'tableContainer'
},scope: {
selected: '='
},templateUrl: 'app/components/table/myTable.html',controller: controller,controllerAs: 'vm',bindToController: true
};
return myTable;
function controller($attrs,$scope,$element) {
var vm = this;
vm.enableMultiSelect = $attrs.multiple === '';
}
}
儿童 angular
.module('app.components')
.directive('myTableRow',myTableRow);
myTableRow.$inject = ['$compile'];
function myTableRow($compile) {
var myTableRow = {
restrict: 'A',require: ['myTableRow','^^myTable'],scope: {
model: '=myTableRow'
},bindToController: true,link: link
};
return myTableRow;
function link(scope,element,attrs,ctrls) {
var self = ctrls.shift(),tableCtrl = ctrls.shift();
if(tableCtrl.enableMultiSelect){
element.prepend(createCheckbox());
}
self.isSelected = function () {
if(!tableCtrl.enableMultiSelect) {
return false;
}
return tableCtrl.selected.indexOf(self.model) !== -1;
};
self.select = function () {
tableCtrl.selected.push(self.model);
};
self.deselect = function () {
tableCtrl.selected.splice(tableCtrl.selected.indexOf(self.model),1);
};
self.toggle = function (event) {
if(event && event.stopPropagation) {
event.stopPropagation();
}
return self.isSelected() ? self.deselect() : self.select();
};
function createCheckbox() {
var checkbox = angular.element('<md-checkbox>').attr({
'aria-label': 'Select Row','ng-click': 'vm.toggle($event)','ng-checked': 'vm.isSelected()'
});
return angular.element('<td class="md-cell md-checkbox-cell">').append($compile(checkbox)(scope));
}
}
function controller() {
}
}
正如您可能看到的那样,它的一个表行指令预先设置了复选框单元格,并且在切换时用于填充绑定到父表指令范围的所选项目数组. 当谈到单元测试表行指令时,我遇到了可以使用元素上的data属性模拟所需控制器的解决方案. 我试过这个,现在我正在尝试测试我的表行指令中的toggle函数来检查它是否将一个项添加到父表指令的scope selected属性: describe('myTableRow Directive',function() {
var $compile,scope,compiledElement,tableCtrl = {
enableMultiSelect: true,selected: []
},controller;
beforeEach(function() {
module('app.components');
inject(function(_$rootScope_,_$compile_) {
scope = _$rootScope_.$new();
$compile = _$compile_;
});
var element = angular.element('<table><tbody><tr my-table-row="data"><td></td></tr></tbody></table>');
element.data('$myTableController',tableCtrl);
scope.data = {foo: 'bar'};
compiledElement = $compile(element)(scope);
scope.$digest();
controller = compiledElement.controller('myTableRow');
});
describe('select',function(){
it('should work',function(){
controller.toggle();
expect(tableCtrl.selected.length).toEqual(1);
});
});
});
但我收到一个错误:
如果我在我的测试中控制台注销控制器的值,它显示为未定义. 我在这方面毫无疑问做错了什么,有人可以赐教吗? 谢谢 UPDATE 我已经遇到过这些帖子: Unit testing a directive that defines a controller in AngularJS How to access controllerAs namespace in unit test with compiled element? 鉴于我正在使用controllerAs语法,我尝试了以下内容: var element = angular.element('<table><tr act-table-row="data"><td></td></tr></table>');
element.data('$actTableController',tableCtrl);
$scope.data = {foo: 'bar'};
$compile(element)($scope);
$scope.$digest();
console.log(element.controller('vm'));
但控制器仍然在控制台日志中未定义. 更新2 我遇到过这篇文章 – isolateScope() returning undefined when testing angular directive 认为它可以帮助我,所以我尝试了以下代替 console.log(compiledElement.children().scope().vm); 但它仍然以未定义的形式返回. compiledElement.children().scope()确实返回一个带有大量有角度的$$前缀范围相关属性的大对象,我可以看到我想要进入的vm控制器深埋在内部,但不确定这是否正确途径 更新3 我遇到过这个article,它涵盖了我正在努力实现的那种东西. 当我尝试在我的测试中实现这种方法时,我可以获得子指令的元素,但我仍然无法检索它的范围: beforeEach(function(){
var element = angular.element('<table><tr act-table-row="data"><td></td></tr></table>');
element.data('$actTableController',tableCtrl);
$scope.data = {foo: 'bar'};
compiledElement = $compile(element)($scope);
$scope.$digest();
element = element.find('act-table-row');
console.log(element);
console.log(element.scope()); //returns undefined
});
我只是想知道这是不是使用链接函数和controllerAs语法? 解决方法
您与发布的原始代码非常接近.我认为你只是在错误的元素上使用
.controller('myTableRow'),因为此时你的compileElement是整个表元素.您需要获取实际的tr子元素才能使myTableRow控制器脱离它.
见下文,具体如下: controller = compiledElement.find('tr').controller('myTableRow');
/* Angular App */
(function() {
"use strict";
angular
.module('app.components',[])
.directive('myTableRow',myTableRow);
function myTableRow() {
return {
restrict: 'A',scope: {
model: '=myTableRow'
},link: link
};
function link($scope,$element,$attrs,$ctrls) {
var self = $ctrls.shift(),tableCtrl = $ctrls.shift();
self.toggle = function() {
// keeping it simple for the unit test...
tableCtrl.selected[0] = self.model;
};
}
function controller() {}
}
})();
/* Unit Test */
(function() {
"use strict";
describe('myTableRow Directive',function() {
var $compile,tableCtrl = {},controller;
beforeEach(function() {
module('app.components');
inject(function(_$rootScope_,_$compile_) {
$scope = _$rootScope_.$new();
$compile = _$compile_;
});
tableCtrl.enableMultiSelect = true;
tableCtrl.selected = [];
var element = angular.element('<table><tbody><tr my-table-row="data"><td></td></tr></tbody></table>');
element.data('$myTableController',tableCtrl);
$scope.data = {
foo: 'bar'
};
compiledElement = $compile(element)($scope);
$scope.$digest();
controller = compiledElement.find('tr').controller('myTableRow');
//console.log(controller); // without the above .find('tr'),this is undefined
});
describe('select',function() {
it('should work',function() {
controller.toggle();
expect(tableCtrl.selected.length).toEqual(1);
});
});
});
})();
<link rel="stylesheet" href="//cdn.jsdelivr.net/jasmine/2.0.0/jasmine.css" /> <script src="//cdn.jsdelivr.net/jasmine/2.0.0/jasmine.js"></script> <script src="//cdn.jsdelivr.net/jasmine/2.0.0/jasmine-html.js"></script> <script src="//cdn.jsdelivr.net/jasmine/2.0.0/boot.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-mocks.js"></script> (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
