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?
There are two prominent approaches when it comes to writing unit tests for button clicks in Angular: either you search the DOM for the button, perform an actual click and verify the expected behavior, or you simply call the component-code that will run when the button is clicked.
fakeAsynclinkWraps a function to be executed in the fakeAsync zone: Microtasks are manually executed by calling flushMicrotasks() . Timers are synchronous; tick() simulates the asynchronous passage of time.
We should Unit Test directives by mocking all dependencies with jasmine mocks and spies. We should also Shallow / Deep Test directives using concrete Components (Compiled DOM). A reasonable approach is to create TestComponent or pick up any component which uses the directive we want to test.
DebugElement is an Angular class that contains all kinds of references and methods relevant to investigate an element as well as component fixture.debugElement.query(By.css('#shan'))
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With