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> (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |