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

链接函数中的AngularJS$setValidity设置错误元素/表单的有效性。在单元测试中不可访问,angularjs,angularjs-directive,Angularjs,Angularjs Directive,我在指令的链接函数中设置表单的有效性,它在实践中起作用。然而,它似乎把验证器放在了错误的元素上,我无法在Jasmine单元测试中访问它。以下是我所做工作的精简版本: 该指令是嵌套表单的一部分,但我不认为这有什么区别: // directive view <tfoot ng-form="formStep"> <tr> <td> <div test-directive ng-model="testDirecti

我在指令的链接函数中设置表单的有效性,它在实践中起作用。然而,它似乎把验证器放在了错误的元素上,我无法在Jasmine单元测试中访问它。以下是我所做工作的精简版本:

该指令是嵌套表单的一部分,但我不认为这有什么区别:

// directive view
<tfoot ng-form="formStep">
    <tr>
        <td>
            <div test-directive ng-model="testDirective.model" ng-change="checkValidity()"></div>
        </td>
    </tr>
</tfoot>
在下面的部分指令中,验证程序以

<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
选项1
在单元测试中,如果I console.log元素.isolateScope().testDirectiveForm.$error,则在未设置输入值的情况下,它包含required的错误。但是,它不包含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();
                }));
            });
        });     
    });
});
//单元测试
描述('testDirective',函数(){
var$范围;
每个之前(angular.mock.module('app'));
beforeach(注入(函数($rootScope){
$scope=$rootScope.$new();
}));
描述('link function',function(){
var createElement、element、isolateScope;
beforeach(注入(函数($compile){
$scope.ngModel;
元素=角度。元素(“”);
attr('ng-model','ngModel');
createElement=函数(){
元素=$compile(元素)($scope);
};
}));
描述('链接后',函数(){
beforeach(注入(函数)(){
createElement();
}));
描述('初始化后',函数(){
beforeach(函数(){
$scope.$apply();
isolateScope=元素。isolateScope();
});
它('.checkValidity应将错误设置为testError',inject(函数($rootScope){
isolateScope.checkValidity();
$rootScope.$digest();
log(isolateScope.testDirectiveForm.$error.testError);
expect(isolateScope.testDirectiveForm.$error.testError).TobedeDefined();
}));
});
});     
});
});

这是怎么回事?我认为我在链接函数中得到的控制器属于该指令,但是如果我在测试中记录“element.scope()”,我就看不到验证器,也看不到任何检查它的方法。有更好的方法来解决这些问题吗?

我通过从测试中的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();
                }));
            });
        });
    });
});
通过在链接函数中使用作用域将验证器放在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();
}));
然而,它与项目中其他工作的完成方式并不一致


希望这些能帮助一些人。谢谢大家的回答。

声明“我正在为表单获取ng模型控制器”没有意义。有一个for-each-form指令和一个for-each-input指令。为什么要为每个输入创建一个表单?此外,您不需要使用ng change来检查有效性。可以使用模型的对象controller@georgeawg在这种情况下,如何获取testDirectiveForm的控制器。我想从指令中访问它。@Wook先生,您能提供一个在这种情况下如何使用验证器的示例吗?它是单元可测试的吗?项目的一个要求是100%的代码覆盖率。实际上,我通过从element.data()获取控制器来解决这个问题
ngModelController.$validators.testError = function(modelValue, viewValue) {
    if (!(viewValue && viewValue.length)) {
        return false;
    } else {
        return true;
    }
};
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();
}));