Tuesday, 31 December 2013

Triggering Events in Angular JS Directive Tests

The best place to perform DOM manipulations in an Angular JS application is in a directive. Sometimes we handle events on the elements wrapped inside the directive to perform required action. The jQlite implementation in Angular JS provides enough APIs to handle these events in the body of the directives. We can use jQuery as well, if API exposed by jQlite is not enough.

One of the primary design goals of Angular JS is testability. Directives are testable too. Since we work directly on DOM with directives, testing becomes a bit tricky. One of such trickier part to test is event. Say, we have a directive that handles blur event on a text box:

app.directive('textBoxBlur', function($window){
  return{
    require:'ngModel',
    link: function(scope, element, attrs, ngModel){
      element.bind('blur', function(e){
        $window.alert("value entered: " + element.val());
      });
    }
  }
});

To call the DOM events manually, jQlite provides a handy method triggerHandler. It is similar to jQuery’s triggerHandler method. It can be fired using jQlite object of any element. Following statement shows this:
elem.triggerHandler('blur');

Since we have to do it repeatedly in tests, it is better to wrap it inside a reusable function as shown below:
changeInputValue = function (elem, value) {
    elem.val(value);
    elem.triggerHandler('blur');
};

Now the above function can be called from any test case to test behaviour of the blur event.
it('Should call alert on losing focus', function(){
  changeInputValue(form.find('input'), "Ravi");
  expect(windowMock.alert).toHaveBeenCalled();
});

Complete sample is available on plnkr: http://plnkr.co/edit/InkyGdIhZiwfe0NC4hyu?p=preview

Happy coding!

1 comment:

  1. Thanks Ravi. Your article just saved me a bunch of searching. triggerHandler does the trick.

    ReplyDelete