19

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

指示:

...
template: "<input ng-model='myModel' ng-change='doIt()' type='text'>" 

测试:

el.find('input').trigger('change') // Dos not trigger ng-change

现场演示(ng-change):http ://plnkr.co/edit/0yaUP6IQk7EIneRmphbW?p=preview


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

template: "<input ng-model='myModel' type='text'>",
link: function(scope, element, attrs) {
  element.bind('change', function(event) {
    scope.doIt();
  });
}

现场演示(手动绑定):http ://plnkr.co/edit/dizuRaTFn4Ay1t41jL1K?p=preview


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

4

5 回答 5

31

从您的解释性评论中:

我在指令的测试中要做的就是检查doIt用户更改输入时调用的内容。

指示的表达式是否ng-change被正确评估实际上是ngModel指令的责任,所以我不确定我是否会以这种方式测试它;相反,我相信ngModelandngChange指令已被正确实现和测试以调用指定的函数,并且只需测试调用函数本身以正确的方式影响指令。端到端或集成测试可用于处理完整使用场景。

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

it('trigger doIt', function() {
  var ngModelController = el.find('input').controller('ngModel');
  ngModelController.$setViewValue('test');
  expect($scope.youDidIt).toBe(true);
});

不过,正如我所说,我觉得这太过分了ngModel's 的职责,打破了自然可组合指令所带来的黑盒。

示例:http ://plnkr.co/edit/BaWpxLuMh3HvivPUbrsd?p=preview


[更新]

在查看了 AngularJS 源代码后,我发现以下内容也有效:

it('trigger doIt', function() {
  el.find('input').trigger('input');
  expect($scope.youDidIt).toBe(true);
});

看起来事件在某些浏览器中有所不同;input似乎适用于 Chrome。

示例:http ://plnkr.co/edit/rbZ5OnBtKMzdpmPkmn2B?p=preview

这是相关的 AngularJS 代码,它使用$sniffer服务来确定要触发的事件:

changeInputValueTo = function(value) {
  inputElm.val(value);
  browserTrigger(inputElm, $sniffer.hasEvent('input') ? 'input' : 'change');
};

即使有这个,我也不确定我会以这种方式测试指令。

于 2013-07-14T06:17:23.100 回答
1

很简单,它适用于您的单元测试环境:

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();
于 2017-05-19T09:05:37.030 回答
1

我用谷歌搜索了“角度指令触发 ng-change”,这个 StackOverflow 问题是我最接近任何有用的问题,所以我会回答“如何在指令中触发 ng-change”,因为其他人一定会登陆这个页面,而且我不知道如何提供此信息。

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

element.controller('ngModel').$viewChangeListeners[0]();

element.trigger("change")element.trigger("input")没有为我工作,我在网上也找不到其他任何东西。

例如,在模糊时触发 ng-change:

wpModule.directive('triggerChangeOnBlur', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            element.on('blur', function () {
                element.controller('ngModel').$viewChangeListeners[0]();
            });
        }
    };
}]);

很抱歉,这不是直接回答 OP 的问题。我将非常乐意就在何处以及如何共享此信息提出一些合理的建议。

于 2016-09-05T21:54:53.690 回答
0

一直试图让这个工作,但每次尝试都失败了。最后得出结论,我的 ng-model-options 在 onUpdate 上设置了去抖动设置,是问题所在。

如果您有去抖,请确保您使用 $timeout 服务刷新。在 Angular mock 中,这个超时服务已经扩展了一个刷新操作,它处理所有未完成的请求/动作。

    var tobetriggered = angular.element(element[0].querySelector('.js-triggervalue'));
    tobetriggered.val('value');
    tobetriggered.trigger('change');
    $timeout.flush();
于 2017-08-31T07:14:48.133 回答
0

我一直在寻找这条简单的线路很长时间。只是为了保存在这里。

如何使用 Karma 从 html-select 中选择值,从而使 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'
于 2016-03-30T16:55:35.480 回答