如何在测试中更新 angularjs 组件 属性 绑定到 element.val 的输入集

How to update angularjs component property binded to input set with element.val in test

我已经实现了 foo 组件,其模板有一个输入(绑定到 fooValue 属性)当输入具有焦点时按下 "enter" 键时调用该组件控制器函数 onEnter 的属性。

我遇到的问题是,在输入中插入一个值(即 "foo3")并按下 "enter" 键后,fooValue 是不更新输入值。

这是片段:

var app = angular.module('app', []);

app.component('foo', {
  template: '<input ng-model="$ctrl.fooValue" enter-key="$ctrl.onEnter()" />',
  controller: function() {
    this.onEnter = function() {
      // this.fooValue is not updated with input value
    };
  },
  bindings: {
    fooValue: '@'
  }
});

app.directive('enterKey', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      element.bind("keydown keypress", function(event) {
        var keyCode = event.which || event.keyCode;

        // If enter key is pressed
        if (keyCode === 13) {
          scope.$apply(function() {
            // Evaluate the expression
            scope.$eval(attrs.enterKey);
          });
        }
      });
    }
  };
});

describe('test', function() {
  describe('foo', function() {
    beforeEach(module('app'));

    var element,
      inputElem;

    beforeEach(inject(function($compile, $rootScope) {
      var fooScope = $rootScope.$new();

      element = angular.element('<foo foo-value="foo1"></foo>');
      element = $compile(element)(fooScope);

      fooScope.$digest();
    }));

    it('should set fooValue with foo3', function() {
      var controller = element.controller('foo');
      inputElem = element.find('input');
      inputElem.val('foo3');
      inputElem.triggerHandler({
        type: 'keydown',
        which: 13
      });

      expect(controller.fooValue).toBe('foo3');
    });
  });
});
<!DOCTYPE html>
<html ng-app="app">

<head>
  <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="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
  <script src="https://code.angularjs.org/1.6.1/angular-mocks.js"></script>
</head>

<body>
</body>

</html>

更新 fooValue 缺少什么?

要更新 fooValue,需要触发 input 事件。如果需要 IE11 支持,请使用 change 事件。

以下片段显示它正在工作:

var app = angular.module('app', []);

app.component('foo', {
  template: '<input ng-model="$ctrl.fooValue" enter-key="$ctrl.onEnter()" />',
  controller: function() {
    this.onEnter = function() {
      // this.fooValue is now updated with input value
    };
  },
  bindings: {
    fooValue: '@'
  }
});

app.directive('enterKey', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      element.bind("keydown keypress", function(event) {
        var keyCode = event.which || event.keyCode;

        // If enter key is pressed
        if (keyCode === 13) {
          scope.$apply(function() {
            // Evaluate the expression
            scope.$eval(attrs.enterKey);
          });
        }
      });
    }
  };
});

describe('test', function() {
  describe('foo', function() {
    beforeEach(module('app'));

    var element,
      inputElem;

    beforeEach(inject(function($compile, $rootScope) {
      var fooScope = $rootScope.$new();

      element = angular.element('<foo foo-value="foo1"></foo>');
      element = $compile(element)(fooScope);

      fooScope.$digest();
    }));

    it('should set fooValue with foo3', function() {
      var controller = element.controller('foo');
      inputElem = element.find('input');
      inputElem.val('foo3');
      inputElem.triggerHandler('input');  // fire the input event to update fooValue with 'foo3'
      // inputElem.triggerHandler('change'); for IE11 
      inputElem.triggerHandler({
        type: 'keydown',
        which: 13
      });

      expect(controller.fooValue).toBe('foo3');
    });
  });
});
<!DOCTYPE html>
<html ng-app="app">

<head>
  <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="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
  <script src="https://code.angularjs.org/1.6.1/angular-mocks.js"></script>
</head>

<body>
</body>

</html>