Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit test angular right-click directive

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?

like image 979
Paul Taylor Avatar asked Jul 18 '13 09:07

Paul Taylor


People also ask

What is correct way to trigger a click event on a button when testing an Angular component?

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.

What is fakeAsync in Angular?

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.

How do you test a jasmine directive?

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.

What is fixture DebugElement?

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'))


1 Answers

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

like image 131
mbfisher Avatar answered Sep 20 '22 14:09

mbfisher