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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21211036/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 20:23:21  来源:igfitidea点击:

jQuery Trigger Event in AngularJS Karma Test

javascriptjqueryangularjsjasminekarma-runner

提问by Justin Noel

I'm trying to test a new directive I'm writing. However, I can't seem to get the keydown event to trigger with jQuery inside Karma/Jasmine.

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

Here is a simplified version of the test :

这是测试的简化版本:

'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);

    });

  });

});

My karma config includes AngularJS and jQuery. Here's that section:

我的业力配置包括 AngularJS 和 jQuery。这是那个部分:

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

When I run the test, I get an error that my input element has no trigger method :

当我运行测试时,我收到一个错误,指出我的输入元素没有触发方法:

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)

At first, you may think that jQuery is not included. However, it is included. If it were not, the test would fail at $.Event.

一开始,您可能认为 jQuery 不包括在内。但是,它包括在内。如果不是,则测试将在 处失败$.Event

Suggestions on getting the keydown event to work on the input?

关于让 keydown 事件对输入起作用的建议?

回答by dcodesmith

I hope this works

我希望这有效

  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

回答by André Werlang

TLDR: load jQuery before AngularJS.

TLDR:在 AngularJS 之前加载 jQuery。

At first, you may think that jQuery is not included. However, it is included. If it were not, the test would fail at $.Event.

一开始,您可能认为 jQuery 不包括在内。但是,它包括在内。如果不是,则测试将在 $.Event 处失败。

You have 2 dependencies on jQuery here:

您在此处对 jQuery 有 2 个依赖项:

  1. $.Event, a direct reference; and
  2. $, indirectly referenced by angular.element();
  1. $.Event,直接引用;和
  2. $, 间接引用angular.element();

When AngularJS is loaded, it looks for a previously loaded jQuery instance, and in case it does exist, it makes elementjust an alias to $. Otherwise it loads a reference to jqLite, which does not have a triggermethod.

当 AngularJS 被加载时,它会寻找一个先前加载的 jQuery 实例,如果它确实存在,它element只是为$. 否则,它会加载对 jqLit​​e 的引用,该引用没有trigger方法。

So, I'm sure you do have jQuery loaded, but that does not mean AngularJS will use it. To do so, you must ensure jQuery is loaded (anywhere) before AngularJS.

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

When angular.element()refers to jqLite, it would never call jQuery, even after jQuery is loaded. So you can only call methods defined on jqLite:

angular.element()引用 jqLit​​e 时,它​​永远不会调用 jQuery,即使在加载 jQuery 之后。所以只能调用jqLit​​e上定义的方法:

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

However, jqLite's triggerHandlerwould not perform event bubbling, it's not reliable to mock raising events. jQuery's triggeris way better.

但是,jqLit​​etriggerHandler不会执行事件冒泡,模拟引发事件是不可靠的。jQuery 的trigger要好得多。

To use jQuery, do this on your HTML:

要使用 jQuery,请在您的 HTML 上执行以下操作:

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

Or on your karma.conf.js:

或者在你的 karma.conf.js 上:

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

Reference:

参考:

Suggestions on getting the keydown event to work on the input?

关于让 keydown 事件对输入起作用的建议?

You have found one approach by working-around the problem. It's not a big deal for your unit tests, where you would want a better DOM library, but now you know what's going on.

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

PS: I really liked answering this one. A question from more than a year, viewed by 6k users, and still no answer to the coreproblem.

PS:我真的很喜欢回答这个问题。一年多的问题,6k用户查看,仍然没有解决核心问题。