AngularJS $ setValidity в функции связывания устанавливает допустимость неправильного элемента / формы.Недоступно в рамках модульного теста - PullRequest
0 голосов
/ 07 мая 2018

Я устанавливаю валидность формы в функции связывания моей директивы, и она работает на практике.Тем не менее, похоже, что он помещает валидатор не в тот элемент, и я не могу получить к нему доступ в модульном тесте Jasmine.Вот урезанная версия того, что я сделал:

Директива является частью вложенной формы, хотя я не думаю, что это имеет значение:

// directive view
<tfoot ng-form="formStep">
    <tr>
        <td>
            <div test-directive ng-model="testDirective.model" ng-change="checkValidity()"></div>
        </td>
    </tr>
</tfoot>

ВФункция связывания, я получаю modelController для формы (или это контроллер для директивы? Мне неясно в этом.)

// directive linking function
(function () {
    'use strict';

    angular.module('app')
        .directive('testDirective', testDirective);

    testDirective.$inject = [];

    function testDirective() {
        return {
            restrict : 'A',
            require: 'ngModel',
            scope : {
            },
            replace : true,
            template: require('./test.directive.partial.html'),
            link: function(scope, element, attributes, ngModelController){
                scope.checkValidity = checkValidity;

                function checkValidity(){
                        ngModelController.$setValidity('testError', false);
                }
            }
        };
    }
})();

В следующей части директивы валидатор заканчиваетсяна

<div class="testDirective"> 

, а не

<div ng-form="testDirectiveForm"> 

Таким образом, конечный результат кода при изменении входных данных будет

<div class="testDirective ng-scope ng-isolate-scope ng-invalid-test-error ng-dirty ng-valid-parse">

(по крайней мере, когда он регистрируется измодульный тест.)

// test.directive.partial.html
<div class="testDirective">
    <div ng-form="testDirectiveForm">
            <label class="radio-inline">
                <input type="radio" ng-model="testModel.test" ng-value="true" required ng-change="checkValidity()" />                           
                <strong>option 1</strong>
            </label>
    </div>
</div>

В модульном тесте, если я console.log element.isolateScope (). testDirectiveForm. $ error, он содержит ошибку, необходимую, если я не установил значение для ввода,Тем не менее, он не содержит ошибку для testError.Кажется, это надевается на элемент над ним.

// Unit test
describe('testDirective', function () {
    var $scope;
    beforeEach(angular.mock.module('app'));

    beforeEach(inject(function($rootScope){
        $scope = $rootScope.$new();
    }));
    describe('link function', function(){
        var createElement, element, isolateScope;
        beforeEach(inject(function($compile){   
            $scope.ngModel;
            element = angular.element('<div test-directive></div>');
            element.attr('ng-model', 'ngModel');
            createElement = function(){
                element = $compile(element)($scope);
            };
        }));
        describe('after link', function () {
            beforeEach(inject(function () {
                createElement();
            }));
            describe('after initialization', function () {
                beforeEach(function () {
                    $scope.$apply();
                    isolateScope = element.isolateScope();
                });
                it('.checkValidity should set the the error to testError', inject(function($rootScope){
                    isolateScope.checkValidity();
                    $rootScope.$digest();

                    console.log(isolateScope.testDirectiveForm.$error.testError);
                    expect(isolateScope.testDirectiveForm.$error.testError).toBeDefined();
                }));
            });
        });     
    });
});

Что здесь происходит?Я думаю, что контроллер, который я получаю в функции связывания, относится к директиве, но я не могу увидеть валидатор или какой-либо способ проверить его, если я зарегистрирую «element.scope ()» в тесте.Есть ли лучший способ сделать это?

1 Ответ

0 голосов
/ 07 мая 2018

Я решил это, получив контроллер модели из element.data () в тесте так:

// Unit test
describe('testDirective', function () {
    var $scope, modelController;
    beforeEach(angular.mock.module('app'));

    beforeEach(inject(function($rootScope){
        $scope = $rootScope.$new();
    }));
    describe('link function', function(){
        var createElement, element, isolateScope;
        beforeEach(inject(function($compile){
            $scope.ngModel;
            element = angular.element('<div test-directive></div>');
            element.attr('ng-model', 'ngModel');
            createElement = function(){
                element = $compile(element)($scope);
            };
        }));
        describe('after link', function () {
            beforeEach(inject(function () {
                createElement();
            }));
            describe('after initialization', function () {
                beforeEach(function () {
                    $scope.$apply();
                    isolateScope = element.isolateScope();
                    modelController = element.data().$ngModelController;
                });
                it('.checkValidity should set the the error to testError', inject(function(){
                    isolateScope.checkValidity();
                    expect(modelController.$error.testError).toBeDefined();
                }));
            });
        });
    });
});

Я попытался использовать $ validators, и это сработало для одного из компонентов, над которым я работаю (с тем же модульным тестом, который действителен). Однако другому компоненту, над которым я работал, не удавалось запускать валидатор при каждом обновлении представления. Может быть, что-то делать с контроллерами вложенных форм? Для этого код выглядит так:

ngModelController.$validators.testError = function(modelValue, viewValue) {
    if (!(viewValue && viewValue.length)) {
        return false;
    } else {
        return true;
    }
};

Мне также удалось получить доступ к форме в изолированной области, поместив валидатор в testDirectiveForm, используя область в функции связывания, например:

function checkValidity(){
    scope.testDirectiveForm.$setValidity('testError', false);
}

Это легко проверить на единицу с тем, что я сделал изначально:

it('.checkValidity should set the the error to testError', inject(function($rootScope){
        isolateScope.checkValidity();
        $rootScope.$digest();

        console.log(isolateScope.testDirectiveForm.$error.testError);
        expect(isolateScope.testDirectiveForm.$error.testError).toBeDefined();
}));

Однако, это не соответствовало тому, как выполняется остальная часть работы в проекте.

Надеюсь, что это кому-нибудь поможет. Спасибо всем за ваши ответы.

...