Acosta
Acosta

Reputation: 1055

how to test $parsers.push and $formatters.push on angular with jasmine

I cannot force angular to fire $parsers.push when updating the input so, having this directive with the above test, how do you fire the $parsers.push ?

mainApp.directive('amountConverter', function() {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function(scope, element, attrs, ngModelController) {
      var isInt = function(value) {
          return !isNaN(parseInt(value, 10)) && (parseFloat(value, 10) == parseInt(value, 10));
        },
        convert = function(initial, multiplier, text) {
          var amount = text.replace(initial, "");
          if (!isInt(amount)) {
            throw " Amount not a number";
          }

          return amount * multiplier;
        };

      //convert data from view format to model format
      ngModelController.$parsers.push(function(value) {
        if (value === null || value === undefined) {
          return null;
        }

        var text = value.toUpperCase();
        var amount = 0;
        var initial = text.substring(text.length - 1);

        if (initial === "B") {
          amount = convert(initial, 1000000000, text);
        } else if (initial === "M") {
          amount = convert(initial, 1000000, text);
        } else if (initial === "K") {
          amount = convert(initial, 1000, text);
        } else if (initial === "T") {
          amount = convert(initial, 1000, text);
        } else {
          return value;
        }

        element[0].value = amount;

        return amount; //converted
      });
    }
  };
});

    describe('Directives', function () {

        var element, scope;

        beforeEach(module('mainApp'));

        beforeEach(inject(function ($compile, $rootScope) {
            scope = $rootScope;
            element = angular.element('<input type="text" data-ng-model="Amount" amount-Converter/>');
            $compile(element)(scope);
                    scope.$digest();
    }));

    //////Jasmine Test
    describe('amountConverter', function () {                  

        it('should return change element state after click to be visible', function () {
                        element.scope().Amount = '10k';
                        element.scope().$apply();
                        expect(element[0].value).toBe('10000');

                    });
                });
            });

Upvotes: 4

Views: 3411

Answers (2)

Moin Haidar
Moin Haidar

Reputation: 1694

= Directive

directive('numbersOnly', function(){
 return {
   require: 'ngModel',
   link: function(scope, element, attrs, ngModelController) {
     ngModelController.$parsers.push(function (inputVal) {
         if (inputVal == undefined) return '' 
         var onlyNumbers = inputVal.replace(/[^0-9]/g, ''); 
         if (onlyNumbers != inputVal) {
            ngModelController.$setViewValue(onlyNumbers);
            ngModelController.$render();
         }         
         return onlyNumbers;         
     });
     }
    };
  })

= Spec

describe('Directive: numbersOnly', function () {

  beforeEach(module('myApp'));

  var rootScope,
    scope,
    element,
    compile;

  beforeEach(inject(function ($rootScope, $compile) {
    scope = $rootScope.$new();
    compile = $compile;
    element = prepareElement("<input numbers-only ng-model='inputValue'></input>");
  }));

  // utility function
  var prepareElement = function (elem) {
    var el = compile(angular.element(elem))(scope);
    body.append(el);
    scope.$digest();
    return el;
  };

  it('should accepts input value if its number', function(){
    element.val('12345');
    element.trigger('input');
    scope.$digest();
    expect(element.val()).toBe('12345');
  });

  it('should not accepts input value if it is not number', function(){
    element.val('not a number');
    element.trigger('input');
    scope.$digest();
    expect(element.val()).toBe('');
  });

  it('should reject other than numbers', function(){
    element.val('%$#$%%%^123456789not a number');
    element.trigger('input');
    scope.$digest();
    expect(element.val()).toBe('123456789');
  });

});

Upvotes: 0

Erin Drummond
Erin Drummond

Reputation: 5526

Taken from the video in Acosta's comment:

The way to make angular do its thing is to trigger the 'input' event on the element (using element.trigger('input'). So in your test, you should be able to do:

element.val("10k");
element.trigger("input");
element.scope().$apply(); //not sure if you even need to do this, video says yes, however on angular 1.3.8 I didnt need to
expect(element.val()).toBe('10000');
expect(element.scope().Amount).toBe('10000');

Upvotes: 3

Related Questions