链接函数中的AngularJS $ setValidity设置错误元素/表单的有效性。在单元测试中无法访问

时间:2018-05-07 03:06:31

标签: angularjs angularjs-directive

我在我的指令的链接功能中设置表单的有效性,它在实践中有效。但是,它似乎将验证器置于错误的元素上,而且我无法在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();
                }));
            });
        });     
    });
});

这里发生了什么?我认为我在链接函数中获得的控制器属于该指令,但是如果我记录了&#34; element.scope(),我无法看到验证器或看到任何方法来检查它。 &#34;在测试中。有没有更好的方法来解决这个问题?

1 个答案:

答案 0 :(得分:0)

我通过在测试中从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();
}));

但是,它并没有与项目中其他工作的完成方式保持一致。

希望其中一些可以帮助某人。谢谢大家的回答。