在AngularJS的Karma测试中触发jQuery事件

6

我正在尝试测试我编写的新指令。但是,在 Karma/Jasmine 环境下,似乎无法使用 jQuery 触发 keydown 事件。

这是测试的简化版本:

'use strict';

describe('', function() {

  var $compile;
  var $scope;

  beforeEach(inject(function(_$compile_, _$rootScope_) {
    $compile = _$compile_;
    $scope = _$rootScope_.$new();
  }));

  describe('Getting Trigger To Work', function() {

    it('Should Trigger a KeyDown Event', function() {

      var el = $compile('<form name="testing"><input id="field1" name="testfield" ng-model="result" type="text" ng-minlength="5" ng-maxlength="50"/></form>')($scope);
      console.log(el);

      var inputEl = el.find('input');
      console.log(inputEl);

      var e = $.Event('keydown');
      e.which = 65;

      inputEl.trigger(e);

    });

  });

});

我的 Karma 配置包括 AngularJS 和 jQuery。以下是该部分内容:

//
files: [
  'lib/angular.js',
  'lib/angular-mocks.js',
  'lib/jquery-1.10.2.min.js',
  'test/**/*Spec.js'
],

当我运行测试时,出现了一个错误,提示我的输入元素没有触发方法:
INFO [watcher]: Changed file "/Volumes/Macintosh HD/dev_libraries/val-on-timeout/test/valOnTimeoutSpec.js".
LOG: Object{0: <form name="testing" class="ng-scope ng-pristine ng-valid"><input id="field1" name="testfield" ng-model="result" type="text" ng-minlength="5" ng-maxlength="50" class="ng-pristine ng-valid"></form>, length: 1}
LOG: Object{0: <input id="field1" name="testfield" ng-model="result" type="text" ng-minlength="5" ng-maxlength="50" class="ng-pristine ng-valid">, length: 1}
Chrome 32.0.1700 (Mac OS X 10.8.5)  testing valOnTimeout Should load FAILED
    TypeError: Object [object Object] has no method 'trigger'
        at null.<anonymous> (/Volumes/Macintosh HD/dev_libraries/val-on-timeout/test/valOnTimeoutSpec.js:79:21)
Chrome 32.0.1700 (Mac OS X 10.8.5): Executed 1 of 1 (1 FAILED) ERROR (0.327 secs / 0.033 secs)

一开始,你可能会认为jQuery没有被包含。然而,它已经被包含了。如果没有的话,在$.Event处测试将会失败。

如何让键盘按下事件在输入框上起作用?


那就是问题所在。[object Object]没有'trigger'方法,因此我无法触发任何事件。 - Justin Noel
抱歉,我的意思是 angular.element(inputEl).trigger('keydown') - dcodesmith
@dcodesmith 谢谢。尝试过了,但没有成功。仍然出现“Object [object Object] has no method 'trigger'”的错误。 - Justin Noel
2个回答

11

我希望这个能够成功

  var e = $.Event('keydown');
  e.which = 65;

  $(inputEl).trigger(e); // convert inputEl into a jQuery object first
  // OR
  angular.element(inputEl).triggerHandler(e); // angular.element uses triggerHandler instead of trigger to trigger events

我在 Twitter 上也收到了一个相同的答案,但是你在这里得到了投票。 $(inputEl).trigger(e) 就解决了问题。谢谢。 - Justin Noel

2

简述: 在加载AngularJS之前要先加载jQuery。

起初,您可能认为没有包含jQuery。但实际上已经包含了。如果没有,测试会在$.Event处失败。

这里有2个对jQuery的依赖关系:

  1. $.Event,一个直接的引用;和
  2. $,通过angular.element()间接引用;

当加载AngularJS时,它会寻找以前加载的jQuery实例,如果存在,则使element成为$的别名。否则,它会加载一个对jqLite的引用,它没有trigger方法。

因此,我确定您已经加载了jQuery,但这并不意味着AngularJS将使用它。为此,您必须确保在AngularJS之前(任何地方)加载jQuery。

angular.element()引用jqLite时,即使在加载jQuery之后,也永远不会调用jQuery。因此,您只能调用在jqLite上定义的方法:

angular.element(inputEl).triggerHandler(e);

然而,jqLite的triggerHandler不会执行事件冒泡,模拟触发事件并不可靠。jQuery的trigger要好得多。

要使用jQuery,请在您的HTML上这样做:

<script src="jquery.js">
<script src="angular.js">

或者在您的 karma.conf.js 文件中:

files: [
  'lib/jquery-1.10.2.min.js',
  'lib/angular.js',
  'lib/angular-mocks.js',
  'test/**/*Spec.js'
],

参考资料:

如何让输入框的键盘按下事件生效?

你已经找到了一种方法来解决这个问题。对于你的单元测试来说,这并不是什么大问题,因为你需要一个更好的DOM库,但现在你知道了发生了什么。

提示:我真的很喜欢回答这个问题。这是一个超过一年时间,被6k用户查看,但仍然没有解决核心问题的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接