我试图对AngularJS 1.5(带有Webpack)组件的(子)控制器进行单元测试,该组件需要父组件和来自另一个模块的控制器。
子控制器结构:
function ChildController () {
var vm = this;
vm.searchText = '';
vm.submit = function() {
var data = {};
data['srch'] = vm.searchText;
vm.parentCtrl.submitTextSearch(data);
};
}
module.exports = ChildController;
子组件:
var template = require('./child.html');
var controller = require('./child.controller');
var childComponent = {
require: {
parentCtrl: '^parent'
},
template: template,
controller: controller,
controllerAs: 'vm'
};
module.exports = childComponent;
所以我想做的是模拟childController的submit()函数所需的parentCtrl。我一直无法找到如何实际做到这一点。我找到了一些类似的子父母指令解决方案并尝试了这些解决方案,例如:通过this child-parent directive example中描述的假HTML元素注入父控制器,并且基本上相同stackoverflow solutions没有结果。我的问题至少在于子控制器和父控制器位于不同的模块中。而且我认为范围技巧并不是Angular 1.5风格的那么多?
我的Jasmine测试的骨架没有我失败的模拟尝试:
describe('child component', function() {
describe('child controller', function() {
var controller;
beforeEach(angular.mock.module('child'));
beforeEach(inject(function(_$componentController_) {
controller = _$componentController_('child');
}))
it('should work', function() {
controller.searchText = "test";
controller.submit();
})
})
})
结果为TypeError: Cannot read property 'submitTextSearch' of undefined
。我该怎样做才能模拟父控制器?由于我在Angular的经验有限,我没有想法。
答案 0 :(得分:4)
在您的情况下,您将parentCtrl
添加为组件的依赖项,因此为了测试它,您还必须模拟父组件并将其分配给控制器。所以你需要做类似的事情:
beforeEach(inject(function(_$componentController_) {
controller = _$componentController_('child');
parentCtrl = _$componentController_('parent');
controller.parentCtrl = parentCtrl;
}))
答案 1 :(得分:1)
使用以下代码将初始化,请检查正在运行的Jasmine单元测试Plunker
var ctrP = $componentController('parentComp');
var ctrl = $componentController('childComp', {}, {
parentCtrl: ctrP
});
您的测试用例应如下所示:
'use strict';
describe('component: heroDetail', function() {
var $componentController, $compile, $rootScope;
beforeEach(module('plunker'));
beforeEach(inject(function(_$componentController_) {
$componentController = _$componentController_;
}));
it('should expose a `hero` object', function() {
var ctrP = $componentController('parentComp');
console.log(ctrP);
var ctrl = $componentController('childComp', {}, {
parentCtrl: ctrP
});
console.log(ctrl);
ctrl.submit('some data');
expect(ctrl.parentCtrl.searchText).toEqual('some data');
});
});
答案 2 :(得分:0)
1。解决方案
在测试中使用新范围实例化父控制器:
mainScope = $rootScope.$new();
$controller('ParentController', {$scope: mainScope});
并在您的子控制器中,使用先前实例化的范围实例化新范围:
childScope = mainScope.$new();
$controller('ChildController', {$scope: childScope});
describe('state', function() {
var mainScope, childScope, grandChildScope;
beforeEach(module('myApp'));
beforeEach(inject(function($rootScope, $controller) {
mainScope = $rootScope.$new();
$controller('MainController', {$scope: mainScope});
childScope = mainScope.$new();
$controller('ChildController', {$scope: childScope});
grandChildScope = childScope.$new();
$controller('GrandChildController', {$scope: grandChildScope});
}));
it('should work', function() {
grandChildScope.searchText = "test";
grandChildScope.submit();
});
});
2。解决方案
子控制器结构:
function ChildController () {
var vm = this;
vm.searchText = '';
vm.submit = function() {
var data = {};
data['srch'] = vm.searchText;
vm.parentCtrl.submitTextSearch(data);
};
}
module.exports = ChildController;
子组件:
var template = require('./child.html');
var controller = require('./child.controller');
var childComponent = {
bindings: {
searchText: 'test'
},
template: template,
controller: controller,
controllerAs: 'vm'
};
module.exports = childComponent;
var ChildController = $componentController('childComponent', null, {...});
ChildController.$onInit();
expect(ChildController.searchText).to.equal('test');
expect(ChildController.submit()).to.equal('*expected result value should come here*');
REFRENCES:
AngularJS documentation - Testing Controllers