Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular directives: It's possible testing that certain characters are rejected in a keypress event?

I've been building a directive that restricts a user from pressing certain invalid characters, in this case, using the keypress event binding to the input element that uses my directive. I've been trying to test this functionality, but i don't understand how to achieve this.

My directive

angular
    .module('gp.rutValidator')
    .directive('gpRutValidator', directive);

  directive.$inject = ['$filter'];

  function directive($filter){
    var ddo = {
      restrict: 'A',
      require: 'ngModel',
      link: linkFn
    };
    return ddo;

    function linkFn(scope, element, attrs, ngModel){

      //valid characters are digits, dash and letter k
      var regexValidKeys = (/[\d\.\-k]/i);

      element.bind('keypress', function(e){

        var key = e.key || String.fromCharCode(e.keyCode);

        if (!regexValidKeys.test(key)) {
          e.preventDefault();
          return false;
        }

      });

    }
  }

My test

describe('Angular Rut Validator Directive',validatorDirectiveSpec);

  function validatorDirectiveSpec(){

    //////////////  GLOBALS   ////////////////////////////////
    var scope, element, evt;
    //////////////  BEFORE EACH ////////////////////////////////
    beforeEach(module('gp.rutValidator'));
    beforeEach(inject(eachSpec));

    function eachSpec($rootScope, $compile){
      element = angular.element('<input ng-model="rut" gp-rut-validator>');
      scope = $rootScope.$new();
      $compile(element)(scope);
      scope.$digest();
    }

    ////////////////// HELPERS ///////////////////////////////////
    function pressKey(keyCode) {
      try {
        // Chrome, Safari, Firefox
        evt = new KeyboardEvent('keypress');
        delete evt.keyCode;
        Object.defineProperty(evt, 'keyCode', {'value': keyCode});
      }
      catch (e) {
        // PhantomJS 
        evt = document.createEvent('Events');
        evt.initEvent('keypress', true, true);
        evt.keyCode = keyCode;
      }
      element[0].dispatchEvent(evt);
    }
    //////////////////   SPECS //////////////////////////////////
    it('1. Should be reject no valid characters', spec1);

    function spec1(){
      var ngModelCtrl = element.controller('ngModel'),
          invalidCharacterKeys = [
                                    'a'.charCodeAt(0),
                                    'z'.charCodeAt(0),
                                    'b'.charCodeAt(0),
                                    '#'.charCodeAt(0)
                                  ];

      invalidCharacterKeys.forEach(function(keyCode){
        pressKey(keyCode);
        scope.$digest();
        expect(scope.rut).toBe('');
      });

    }

  }

But I get the error Expected undefined to be ''.

What am I doing wrong?

Example in Codepen => http://codepen.io/gpincheiraa/pen/ozWyvA

like image 608
Gonzalo Pincheira Arancibia Avatar asked Sep 27 '16 03:09

Gonzalo Pincheira Arancibia


1 Answers

How about replacing the Event.prototye.preventDefault:

var original = Event.prototype.preventDefault;
Event.prototype.preventDefault = function(){
    original.bind(this);
    handlers.filter((handler) => handler.keyCode == this.keyCode).forEach((handler)=>handler.handle(this));
    handlers = handlers.filter((handler)=> handler.keyCode != this.keyCode);
}

and make him call a predefined Callback:

function pressKey(keyCode, cb) {
        try {
            // Chrome, Safari, Firefox
            handlers.push({keyCode : keyCode, handle: cb});
            evt = new KeyboardEvent('keypress');
            delete evt.keyCode;
            Object.defineProperty(evt, 'keyCode', {'value': keyCode});
            element[0].dispatchEvent(evt);
        }
        catch (e) {
            // PhantomJS 
            evt = document.createEvent('Events');
            evt.initEvent('keypress', true, true);
            evt.keyCode = keyCode;
            element[0].dispatchEvent(evt);
        }
    }

and then call pressKey like this:

pressKey(keyCode, (event)=>{expect(event.keyCode).toBe(keyCode)}));

I am not 100% sure if this is what you've asked for...

like image 51
Coco Avatar answered Nov 13 '22 12:11

Coco