我如何在我的AngularJS指令testing中模拟点击事件?

我试着按照我编写的指令的ng-directive-testing回购的格式。 当用户点击一个元素时,该指令基本上呈现一个叠加层。 这里是指令(简化):

mod.directive('uiCopyLinkDialog', function(){ return { restrict: 'A', link: function(scope, element, attrs) { var $elm = angular.element(element); element.bind('click', function(event) { $elm.addClass('test'); }); } }; }); 

我正在写的testing看起来像这样:

 describe('pre-compiled link', function () { beforeEach(mocks.inject(function($compile, $rootScope) { scope = $rootScope; element = angular.element('<span class="foo" ui-copy-link-dialog="url"></span>'); $compile(element)(scope); scope.$digest(); })); it("should change the class when clicked", function () { element.click(); // this returns "'undefined' is not a function" element[0].click(); // so does this $(elm).click(); // this uses jquery and doesn't *seem* to fail waits(500); // hack to see if it was a race condition expect(elm.className).toContain('test'); // always fails }); }); 

您可以在testing中看到,我尝试了几种方法来触发链接上的click()事件,其中大多数都会提供undefined错误。

有谁能告诉我我在做什么错在这里? 阅读这些例子听起来像是正确的语法,但我的testing运行者(Karma via Grunt)不想玩球。

你可以使用JHQLite的一部分triggerHandler。

我用它来触发一个指令上的点击事件…

 element = angular.element("<div myDirective-on='click'></div>"); compiled = $compile(element)($rootScope); compiled.triggerHandler('click'); 

此博客文章中提供了完整示例: http : //sravi-kiran.blogspot.co.nz/2013/12/TriggeringEventsInAngularJsDirectiveTests.html

所以这个问题在PhantomJS中是一个问题:当元素实际上并不在文档的任何地方,而是在内存中(这是我的理论,无论如何),一些对元素起作用的事件似乎并不会被触发。 要解决这个问题,我不得不使用这个函数来触发元素上的click事件:

 define(function () { return { click: function (el) { var ev = document.createEvent("MouseEvent"); ev.initMouseEvent( "click", true /* bubble */, true /* cancelable */, window, null, 0, 0, 0, 0, /* coordinates */ false, false, false, false, /* modifier keys */ 0 /*left*/, null ); el.dispatchEvent(ev); } }; }); 

虽然其他的东西比较困难,但我也想编写一个testing,确保给定的表单input有重点,但是使用PhantomJS获取这个值几乎是不可能的,因为我猜如果浏览器没有屏幕,表示。 任何需要这个的人都可以看一下CasperJS,它为这些需求提供了一个简单的API。

我也遇到了麻烦。 似乎对于我编译的任何元素来说, click()对PhantomJS来说似乎都不起作用。 它总是返回undefined。

虽然不如实际的点击,你可以通过ng-click来访问指令的function,通过它的隔离范围来模拟点击:

 var element = $compile('<a ng-click="myfunc()">Click me</a>')(scope); var isolateScope = element.isolateScope(); isolateScope.myfunc(); scope.$digest(); /* check that things changed ... */ 

所以我的解决scheme是实际将元素附加到正文。 由于根本问题是phantomJs不会为内存中的元素触发事件,因此追加每个元素似乎更简单,以便事件真正起作用。

 afterEach(function(){ $('body').empty(); }); it('should do something when clicked', function(){ element = $compile('<div my-directive></div>')($scope); $('body').append(element); // fire all the watches, so the scope expressions will be evaluated $rootScope.$digest(); $(element).find('.my-input').click(); }); 

你可以使用angular-test-runner库,testing如下所示:

 const testRunner = require('angular-test-runner'); describe('directive', () => { let app; const {expectElement, click} = testRunner.actions; beforeEach(() => { app = testRunner.app(['mod']); }); it("should add class when clicked", function () { const html = app.runHtml('<span class="foo" ui-copy-link-dialog="url"></span>'); html.perform( click.in('.foo') ); html.verify( expectElement('.foo').toHaveClass('test') ); }); }); 

如何包括angular-scenario ,然后使用browserTrigger(element, 'click')