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:
M
I choose an alternative approach. You can use a directive to bind specific action on right click, using the
contextmenu
event:Code example on JSFiddle
The following javascript function will fire the contextmenu event on the JQueryLite element passed to it: