1

I built a new directive in Angular (1.2.29) and I am trying to test it using karma, however I am having some problems when checking if the field is invalid, it seems it's always valid.

Here is my directive:

var EmailOrUrlValidation = function emailOrUrlValidation() {

        console.log("on directive 0");

        return {
            require: 'ngModel',
            restrict: 'A',
            scope: {
                checkDirty: '=validationCheckDirty'
            },
            link: function (scope, element, attrs, ctrl) {

                console.log("on directive 1");

                scope.$watch(function () {
                    scope.checkDirty = scope.checkDirty ? true : false;
                    element.attr('maxlength', 50);
                    ctrl.$parsers.unshift(validateEmailOrUrl);
                    ctrl.$formatters.unshift(validateEmailOrUrl);
                });

                function validateEmailOrUrl(value) {
                    console.log("on directive 2");
                    var urlRegexp = "myurlregex";
                    var emailPattern = "myemailregex";

                    if (!value) { 
                        ctrl.$setValidity("valid", true);

                    } else if (scope.checkDirty && !ctrl.$dirty) { 
                        ctrl.$setValidity("valid", true);

                    } else { 
                        var emailRegex = new RegExp(emailPattern);

                        var emailOrUrlValid = urlRegexp.test(value) || emailRegex.test(value);
                        ctrl.$setValidity("valid", emailOrUrlValid);
                    }
                    return value;
                }
            }
        };
    };

 this.app = angular.module('shared.validations', [])
                     .directive('emailOrUrlValidation', [emailOrUrlValidation])

Here is my unit testing (I followed this example https://stackoverflow.com/a/22772504/1031021):

describe('EmailOrUrlValidation tests', function () {
    var $scope, form, element;
    beforeEach(module("shared.validations"));
    beforeEach(inject(function ($compile, $rootScope) {
        $scope = $rootScope;
        element = angular.element(
            '<form name="form">' +
                '<input data-ng-model="model.emailorurl" name="emailorurl" email-or-url-validation data-ng-required="true" validation-check-dirty="true" />' +
            '</form>'
        );
        $scope.model = { emailorurl: null }
        $compile(element)($scope);
        form = $scope.form;
    }));
    describe('invalid url', function () {
        it('should pass with valid url', function () {

            form.emailorurl.$setViewValue('www.google.pt');
            $scope.$digest();

            expect(form.emailorurl.$invalid).to.be.false;
        });
        it('should not pass with invalid url', function () {

            form.emailorurl.$setViewValue('testing');
            $scope.$digest();

            expect(form.emailorurl.$invalid).to.be.true;
        });
    });
});

However one of the assertions fail, because $invalid is always false...

I inserted some logs inside the function validateEmailOrUrl and its never shown on my console, however logs outside of function appear, I assume the function its not being triggered.

Can someone help me? What is wrong here?

TiagoM
  • 3,458
  • 4
  • 42
  • 83
  • The docs suggest that `$setViewValue` does not trigger a call to the model validators. Try updating the ng-model directly in your test by assigning a value to `$scope.model.emailorurl`. Also I assume that you've replaced `urlRegexp` and `emailPattern` with real regExs? https://docs.angularjs.org/api/ng/type/ngModel.NgModelController#$setViewValue – bags Jan 16 '18 at 20:55
  • I tried your solution, replacing form.emailorurl.$setViewValue('testing') to $scope.model.emailorurl = "testing" but still didn't work, the function validateEmailOrUrl in my directive is not triggered :( and yes I am using real regExs, I just didnt paste them there because it was irrelevant to the question and would make the question too big... do you have any other solution? thanks – TiagoM Jan 17 '18 at 09:38

1 Answers1

0

I made it working, changing my unit test to the following:

describe('EmailOrUrlValidation tests', function() {

    var $scope,
        form,
        element;

    beforeEach(module("shared.validations"));

    beforeEach(inject(function($compile, $rootScope) {
        $scope = $rootScope;
        element = angular.element(
            '<form name="form">' +
            '<input data-ng-model="model.emailorurl" name="emailorurl" email-or-url-validation data-ng-required="true" validation-check-dirty="true" />' +
            '</form>'
        );

        $scope.model = { emailorurl: null }
        $compile(element)($scope);
        form = $scope.form;
    }));

    describe('invalid url', function () {
        it('email address without domain should not be valid', function () {
            $scope.$digest();
            var dirElementInput = element.find('input');
            angular.element(dirElementInput).val('teste@www').trigger('input');
            expect(form.emailorurl.$valid).to.be.false;

        });

        it('email address with domain should be valid', function () {
            $scope.$digest();
            var dirElementInput = element.find('input');
            angular.element(dirElementInput).val('teste@www.com').trigger('input');
            expect(form.emailorurl.$valid).to.be.true;

        });

        it('url address starting with http should not be valid', function() {
                $scope.$digest();
                var dirElementInput = element.find('input');
                angular.element(dirElementInput).val('http://www.google.com').trigger('input');
                expect(form.emailorurl.$valid).to.be.false;

        });

        it('url address starting with https should not be valid', function () {
            $scope.$digest();
            var dirElementInput = element.find('input');
            angular.element(dirElementInput).val('https://www.google.com').trigger('input');
            expect(form.emailorurl.$valid).to.be.false;

        });

        it('url address starting without http should be valid', function () {
            $scope.$digest();
            var dirElementInput = element.find('input');
            angular.element(dirElementInput).val('www.google.pt').trigger('input');
            expect(form.emailorurl.$valid).to.be.true;

        });

        it('random text should not be valid', function () {
            $scope.$digest();
            var dirElementInput = element.find('input');
            angular.element(dirElementInput).val('jdsfvdsfg').trigger('input');
            expect(form.emailorurl.$valid).to.be.false;

        });
    });
});
TiagoM
  • 3,458
  • 4
  • 42
  • 83