如何在AngularJS指令测试中触发ng更改

如何在AngularJS指令测试中触发ng更改,angularjs,angularjs-directive,Angularjs,Angularjs Directive,我有下面的AngularJS指令,它创建了一个input元素。输入具有运行doIt()函数的ng change属性。在指令的单元测试中,我想检查当用户更改输入时是否调用了doIt函数。但测试没有通过。尽管手动测试时它在浏览器中工作 指令: ... template: "<input ng-model='myModel' ng-change='doIt()' type='text'>" 现场演示(ng更改): 现在,如果我手动绑定change事件,而不是使用ngchange属性,

我有下面的AngularJS指令,它创建了一个
input
元素。输入具有运行
doIt()
函数的
ng change
属性。在指令的单元测试中,我想检查当用户更改输入时是否调用了
doIt
函数。但测试没有通过。尽管手动测试时它在浏览器中工作

指令:

...
template: "<input ng-model='myModel' ng-change='doIt()' type='text'>" 
现场演示(ng更改):


现在,如果我手动绑定
change
事件,而不是使用
ngchange
属性,则测试通过

template: "<input ng-model='myModel' type='text'>",
link: function(scope, element, attrs) {
  element.bind('change', function(event) {
    scope.doIt();
  });
}
模板:“”,
链接:函数(范围、元素、属性){
元素绑定('change',函数(事件){
scope.doIt();
});
}
现场演示(手动绑定):



有没有办法使用
ng change
并使其可测试?谢谢。

根据您的解释性意见:

在指令的测试中,我要做的就是检查当用户更改输入时是否调用了
doIt

ng change
指示的表达式是否正确计算实际上是
ngModel
指令的责任,因此我不确定是否会以这种方式进行测试;相反,我相信
ngModel
ngChange
指令已经正确实现和测试,以调用指定的函数,并且只需测试调用函数本身是否以正确的方式影响指令。可以使用端到端或集成测试来处理完全使用场景

也就是说,您可以获得驱动
ngModel
更改回调的
ngModelController
实例,并自己设置视图值:

it('trigger doIt',function(){
var ngModelController=el.find('input').controller('ngModel');
ngModelController.$setViewValue('test');
期望($scope.youDidIt).toBe(true);
});
不过,正如我所说,我觉得这太牵扯到了
ngModel
的责任,打破了自然可组合指令带来的黑盒

例如:


[更新]

在查看AngularJS源代码后,我发现以下代码也适用:

it('trigger doIt',function(){
el.find('input')。trigger('input');
期望($scope.youDidIt).toBe(true);
});
在某些浏览器中,事件似乎有所不同<代码>输入似乎适用于Chrome

例如:

下面是,它使用
$sniffer
服务确定要触发的事件:

changeInputValueTo=函数(值){
输入值(值);
browserTrigger(inputElm,$sniffer.hasEvent('input')?'input':'change');
};

即使这样,我也不确定是否会用这种方式测试指令。

我一直在寻找这条简单的线路。 只是为了把它保存在这里

如何从html select中选择值,使用Karma,从而使ng change函数工作

HTML:

控制器或指令JS:

  $scope.itemTypes = [{name: 'Some name 1', value: 'value_1'}, {name: 'Some name 2', value: 'value_2'}]

  $scope.itemTypeSelected = function () {
    console.log("Yesssa !!!!");
  };
业力测试片段:

  angular.element(element.find("#selectedItemType")[0]).val('value_1').change();
  console.log("selected model.selectedItemType", element.isolateScope().model.selectedItemType);
控制台:

'Yesssa !!!!'
'selected model.selectedItemType', 'value_1'
我在谷歌上搜索了“angular directive trigger ng change”,这个StackOverflow问题是我最接近于任何有用的问题,因此我将回答“如何在指令中触发ng change”,因为其他人一定会登陆此页面,我不知道如何提供此信息

在指令的link函数内,这将触发元素上的ng change函数:

element.controller('ngModel').$viewChangeListeners[0]();
element.trigger(“change”)
element.trigger(“input”)
对我不起作用,我在网上也找不到任何东西

例如,在模糊时触发ng更改:

wpModule.directive('triggerChangeOnBlur', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.on('blur', function () {
                element.controller('ngModel').$viewChangeListeners[0]();
            });
        }
    };
}]);
很抱歉,这没有直接回答OP的问题。我非常乐意就在何处以及如何共享这些信息听取一些合理的建议。

简单且有效 在单元测试环境中:

spyOn(self, 'updateTransactionPrice');


var el = compile('<form name="form" latest novalidate json-schema="main.schema_discount" json-schema-model="main._data"><input type="text" ng-model="main._data.reverse_discount" ng-class="{ \'form-invalid\': form.reverse_discount.$invalid }" ng-change="main.transactionPrice(form);" name="reverse_discount" class="form-control-basic" placeholder="" ng-disabled="!main.selectedProduct.total_price"></form>')(scope);
el.find('input').triggerHandler('change');

expect(self.updateTransactionPrice).toHaveBeenCalled();
spyOn(self,'updateTransactionPrice');
var el=编译(“”)(范围);
el.find('input').triggerHandler('change');
expect(self.updateTransactionPrice).tohaveBeenCall();

一直在尝试使其工作,但每次尝试都失败。最后得出结论,我的ng模型选项在onUpdate上具有去盎司设置,这就是问题所在

如果有解盎司,请确保使用$timeout服务刷新。在angular mock中,此超时服务已通过刷新操作扩展,该操作处理所有未完成的请求/操作

    var tobetriggered = angular.element(element[0].querySelector('.js-triggervalue'));
    tobetriggered.val('value');
    tobetriggered.trigger('change');
    $timeout.flush();

ng更改是在模型更改时触发的,而不是事件。为什么不测试一下你的“doIt”fn的控制器代码?@marko,谢谢你的提问。在指令的测试中,我要做的就是检查当用户更改输入时是否调用了doIt。doIt本身将在指令的测试中被模拟,因为正如您所建议的,它已经在控制器的测试中进行了测试。关于事件,我认为
input
用于文本输入等,而
change
用于选择框和单选按钮。至少这是我在PhantomJS上运行测试的原因。看来browserTrigger只出现在angular-scenario.js中。这意味着它只用于e2e测试,对吗?我不能将此函数用于单元测试,我相信这是故意的。@unludo;我的观点是,AngularJS源代码是为了在某些浏览器中触发不同的事件而编写的。理想情况下,您可以问一个单独的问题,然后自己回答(听起来很奇怪,但建议这样做)。我也在寻找一些不太符合OP或您的问题的东西,如果有专门的问题,我会更快地找到答案。
    var tobetriggered = angular.element(element[0].querySelector('.js-triggervalue'));
    tobetriggered.val('value');
    tobetriggered.trigger('change');
    $timeout.flush();