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?
I've just had exactly the same issue and this was my solution...
Use triggerHandler to dispatch an event, then test that the supplied function is called:
var called;
$rootScope.myFunction = function() {
called = true;
}
var element = $compile('<div my-right-click="myFunction"></div>')($rootScope);
element.triggerHandler('contextmenu');
expect(called).toEqual(true);
M
The following javascript function will fire the contextmenu event on the JQueryLite element passed to it:
//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');
}
}
I choose an alternative approach. You can use a directive to bind specific action on right click, using the contextmenu
event:
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});
});
});
};
});
来源:https://stackoverflow.com/questions/17720009/unit-test-angular-right-click-directive