Tag Archives: testing

AngularJS JavaScript

AngularJS: testing keydown listener

Working with AngularJS is really great experience. This framework comes with many handy features. One of them is build-in support for unit testing. In this post I want to show how to test keydown event listener.

I was recently working on performing some action when user press ESC key. Basically implementation is easy:

angular.module('app').directive('handleEsc', [
  '$document',
  function (
    $document
  ) {
    var ESC_KEY_CODE = 27;

    return {
      scope: {
        handleEsc: '&'
      },
      link: function (scope, element, attrs) {
        /**
         * Create handler for keydown event
         */
        function escHandler (event) {
          if (event.keyCode === ESC_KEY_CODE) {
            scope.handleEsc();
          }
        }

        /**
         * Attach handler to event
         */
        $document.on('keydown', escHandler);

        /**
         * Clean on destroy
         */
        scope.$on('$destroy', function () {
          $document.off('keydown', escHandler);
        });
      }
    };
  }
]);

So what this code is doing? First of all it creates isolated scope with binding method from parent scope by using &. Then in link function it is defining handler for keydown event and attaching this to document. In such cases it is necessary to unregister listener when in order to prevent memory leakage and this is done on scope destroy event.

Now lets move to the interesting part!

Testing keydown

I was looking for solution for a really long time. Finally my more experienced friends helped me.

'use strict';

describe('Directive: handleEsc', function() {
  var scope;
  var $compile;
  var $document;

  beforeEach(angular.mock.module('app'));

  var element = null;
  /**
   * Lets call scope.close() method on ESC key event
   */
  var template = '<div handle-esc="close()"></div>';

  beforeEach(inject(function($injector) {
    $compile  = $injector.get('$compile');
    scope     = $injector.get('$rootScope').$new();
    $document = $injector.get('$document');
  }));

  beforeEach(function() {
    element = $compile(template)(scope);
    /**
     * Create method and spyOn it.
     */
    scope.close = function() {};
    spyOn(scope, 'close');
  });

  function triggerEscKeyDown() {
    /**
     * Create KeyboardEvent
     */
    var e = new window.KeyboardEvent('keydown', {
      bubbles: true,
      cancelable: true,
      shiftKey: true
    });

    /**
     * Assing 27 as keyCode
     */
    delete e.keyCode;
    Object.defineProperty(e, 'keyCode', {'value': 27});

    $document[0].dispatchEvent(e);
  }

  it('should call callback function when the event happens', function() {
    triggerEscKeyDown();
    expect(scope.close).toHaveBeenCalled();
  });

  it('deregisters on scope $destroy', function() {
    scope.$destroy();
    triggerEscKeyDown();
    expect(scope.close).not.toHaveBeenCalled();
  });

});

As you can see in this test I had to use native KeyboardEvent in order to test my directive. As was not able to find any other working example with test for keydown listener. If you know other solution please share in comments.

Agile

Done, done, done and done

While working in big projects we often try to get some story points instead of making story done. After some time we are not even sure if functionality is still working correctly. But there is a solution.

I recently read very interesting book: The Art of Agile Development by James Shore. Between many important information I found one thing that is really crucial.

read more »

Agile

Agile in some “agile” company

In the past I was working in some small company (about 15 people, 7-10 developers) which was telling every customer that they are agile. That they use agile methodology to build solutions, that they bring products with high quality, that they can quickly change software according to requirements, etc. read more »