tl; dr:ソリューションは3番目のコードブロックにあります。
が、プログラムではないという態度でngModelController
を取得する方法はありません。 ;)
あなたはそれをプログラム的に得ることができます。ちょっとしたロータリーです。そうする方法はin the code for ngMock
's $componentController
service(ここで言い換えれば)です。それをルックアップするために$injector.get('ngModelDirective')
を使用して、コントローラ機能はcontroller
プロパティとして、それに添付されます。
this.$get = ['$controller','$injector', '$rootScope', function($controller, $injector, $rootScope) {
return function $componentController(componentName, locals, bindings, ident) {
// get all directives associated to the component name
var directives = $injector.get(componentName + 'Directive');
// look for those directives that are components
var candidateDirectives = directives.filter(function(directiveInfo) {
// ...
});
// ...
// get the info of the component
var directiveInfo = candidateDirectives[0];
// create a scope if needed
locals = locals || {};
locals.$scope = locals.$scope || $rootScope.$new(true);
return $controller(directiveInfo.controller, locals, bindings, ident || directiveInfo.controllerAs);
};
}];
あなたがそれをインスタンス化するとき$element
と$attrs
ためngModelControllerの地元の人々を提供する必要がありますが。 The test spec for ngModel
demonstrates exactly how to do this in its beforeEach
call:だから
beforeEach(inject(function($rootScope, $controller) {
var attrs = {name: 'testAlias', ngModel: 'value'};
parentFormCtrl = {
$$setPending: jasmine.createSpy('$$setPending'),
$setValidity: jasmine.createSpy('$setValidity'),
$setDirty: jasmine.createSpy('$setDirty'),
$$clearControlValidity: noop
};
element = jqLite('<form><input></form>');
scope = $rootScope;
ngModelAccessor = jasmine.createSpy('ngModel accessor');
ctrl = $controller(NgModelController, {
$scope: scope,
$element: element.find('input'),
$attrs: attrs
});
//Assign the mocked parentFormCtrl to the model controller
ctrl.$$parentForm = parentFormCtrl;
}));
、私たちが必要とするものに、私たちはこのような仕様を取得することを適応:
describe('Unit: myComponent', function() {
var $componentController,
$controller,
$injector,
$rootScope;
beforeEach(inject(function (_$componentController_, _$controller_, _$injector_, _$rootScope_) {
$componentController = _$componentController_;
$controller = _$controller_;
$injector = _$injector_;
$rootScope = _$rootScope_;
}));
it('should update its ngModel value accordingly', function() {
var ngModelController,
locals
ngModelInstance,
$ctrl;
locals = {
$scope: $rootScope.$new(),
//think this could be any element, honestly, but matching the component looks better
$element: angular.element('<my-component></my-component>'),
//the value of $attrs.ngModel is exactly what you'd put for ng-model in a template
$attrs: { ngModel: 'value' }
};
locals.$scope.value = null; //this is what'd get passed to ng-model in templates
ngModelController = $injector.get('ngModelDirective')[0].controller;
ngModelInstance = $controller(ngModelController, locals);
$ctrl = $componentController('myComponent', null, { ngModel: ngModelInstance });
$ctrl.doAThingToUpdateTheModel();
scope.$digest();
//Check against both the scope value and the $modelValue, use toBe and toEqual as needed.
expect(ngModelInstance.$modelValue).toBe('some expected value goes here');
expect(locals.$scope.value).toBe('some expected value goes here');
});
});
補遺を:あなたはまた、代わりにbeforeEach
でngModelDirective
を注入して設定することで、さらにそれを簡素化することができますあなたが$controller
のようなサービスと同じように、コントローラ機能を含むdescribe
ブロックのvar。
describe('...', function() {
var ngModelController;
beforeEach(inject(function(_ngModelDirective_) {
ngModelController = _ngModelDirective_[0].controller;
}));
});