5

I want to write a Jasmine unit test for an AngularJS directive. The directive simply binds a contextmenu event handler function to the element:

var myDirectives = angular.module('myApp.directives', []);

myDirectives.directive('myRightClick', ['$parse', function ($parse) {
    return function (scope, element, attrs) {
        var fn = $parse(attrs.myRightClick);
        element.bind('contextmenu', function (event) {
            scope.$apply(function () {
                event.preventDefault();
                fn(scope, { $event: event });
            });
        });
    };
}]);

<div my-right-click="myFunction"></div>

Unit test:

describe('Unit Test Directives', function () {
    var $compile;
    var $rootScope;

    beforeEach(module('myClientApp.directives'));

    beforeEach(inject(function (_$compile_, _$rootScope_) {
        $compile = _$compile_;
        $rootScope = _$rootScope_;
    }));

    it('should wire a contextmenu event binding for the element', function () {
        // Compile a piece of HTML containing the directive
        var element = $compile("<div my-right-click='myFunction'></div>")($rootScope)[0];
        // Check that the compiled element contains the templated content
        expect(element.attributes["my-right-click"].value).toEqual("myFunction");
        expect(element.attributes["oncontextmenu"]).toNotEqual(undefined);
    })
});

The unit test fails on the last assertion, because the element oncontextmenu attribute is undefined. However, the directive correctly invokes the function in the application itself. How can I determine in a test that a function has been correctly bound to the element's oncontextmenu event?

Edit

Or, as an alternative and better approach, how can I wire up an event handler and invoke it via the directive in the test so that I can check that it actually gets called?

4

3 回答 3

10

我刚刚遇到了完全相同的问题,这是我的解决方案...

使用triggerHandler调度一个事件,然后测试提供的函数是否被调用:

var called;
$rootScope.myFunction = function() {
    called = true;
}

var element = $compile('<div my-right-click="myFunction"></div>')($rootScope);
element.triggerHandler('contextmenu');
expect(called).toEqual(true);

于 2013-12-19T15:00:01.343 回答
2

以下 javascript 函数将在传递给它的 JQueryLite 元素上触发 contextmenu 事件:

//simulate user right-clicking on the element and check handler gets called
function fireContextMenuEvent(element) {
    if (document.createEvent) {
        var ev = document.createEvent('HTMLEvents');
        ev.initEvent('contextmenu', true, false);
        element.dispatchEvent(ev);
    } else { // Internet Explorer
        element.fireEvent('oncontextmenu');
    }
}
于 2013-07-23T11:43:37.267 回答
1

我选择了另一种方法。您可以使用指令在右键单击时绑定特定操作,使用contextmenu事件:

app.directive('ngRightClick', function($parse) {
    return function(scope, element, attrs) {
        var fn = $parse(attrs.ngRightClick);
        element.bind('contextmenu', function(event) {
            scope.$apply(function() {
                event.preventDefault();
                fn(scope, {$event:event});
            });
        });
    };
});

JSFiddle 上的代码示例

于 2013-07-18T11:43:11.473 回答