测试修改Karma/Jasmine中其他范围的AngularJS指令

测试修改Karma/Jasmine中其他范围的AngularJS指令,angularjs,angularjs-directive,jasmine,angularjs-scope,karma-runner,Angularjs,Angularjs Directive,Jasmine,Angularjs Scope,Karma Runner,参考: 案例 我有一个名为editable的指令,它接受一个ng模型,并创建一个可切换/可编辑字段。指令工作正常,并且父范围更新正确,指令的实际功能没有问题。不过,我似乎无法编写一个支持这一点的测试。我花了很长时间才让指令在所有警告下正常工作,所以我真的想进行一些测试,以确保它在所有不同的情况下都能继续工作 指令(有效) 我不能确定哪些部分是相关的,所以我把整件事都包括进去了 app.directive('editable', ['$templateCache', '$compile',

参考:

案例 我有一个名为editable的指令,它接受一个
ng模型
,并创建一个可切换/可编辑字段。指令工作正常,并且父范围更新正确,指令的实际功能没有问题。不过,我似乎无法编写一个支持这一点的测试。我花了很长时间才让指令在所有警告下正常工作,所以我真的想进行一些测试,以确保它在所有不同的情况下都能继续工作

指令(有效) 我不能确定哪些部分是相关的,所以我把整件事都包括进去了

app.directive('editable',
    ['$templateCache', '$compile',
    function ($templateCache, $compile) {
        return {
            restrict: 'A',
            transclude: true,
            templateUrl: 'template/directives/editable.html',
            replace: true,
            require: 'ngModel',
            scope: true,
            compile: function(element, attrs, transcludeFn) {

                return function (scope, iElement, iAttrs, ctrl) {

                    var validityId = 'editable-' + scope.$id;

                    scope.lastSavedValue = iElement.find('input').val();

                    scope.storeValue = function() {
                        scope.lastSavedValue = iElement.find('input').val();
                    };

                    scope.edit = function() {
                        scope.storeValue();
                        scope.editing = true;
                        $('input', iElement).focus().select();
                        ctrl.$setValidity(validityId, true);
                    };

                    scope.ok = function() {
                        var inputCtrl = iElement.find('input').controller('ngModel');
                        if(inputCtrl.$valid === true) {
                            scope.editing = false;
                            scope.value = inputCtrl.$viewValue;
                            ctrl.$setValidity(validityId, false);
                            ctrl.$setViewValue(inputCtrl.$viewValue); // Not sure (why) this is needed
                        }
                    };

                    scope['delete'] = function() {
                        scope.deleted = true;
                        scope.editing = false;
                    };

                    scope.undo = function() {
                        var inputCtrl = iElement.find('input').controller('ngModel');
                        if(scope.lastSavedValue) {
                            inputCtrl.$setViewValue(scope.lastSavedValue);
                            scope.value = scope.lastSavedValue;
                            ctrl.$setViewValue(scope.lastSavedValue);
                        }
                        iElement.find('input').val(scope.value);
                        scope.editing = false;
                        scope.deleted = false;
                        ctrl.$setValidity(validityId, false);
                    };

                    transcludeFn(scope, function(clone) {
                        var $editingReplacement = $(clone).filter('[editing]');
                        var $viewingReplacement = $(clone).filter('[viewing]');
                        var $deletedReplacement = $(clone).filter('[deleted]');
                        var $viewingControls = $('.editable-view-container .controls', iElement);
                        var $editingControls = $('.editable-input-container .controls', iElement);
                        var $deletedControls = $('.editable-delete-container .controls', iElement);
                        if($editingReplacement.length) {
                            $('.editable-input-container', iElement).html($editingReplacement.html());
                            $('.editable-input-container', iElement).append($editingControls);
                            $compile($('.editable-input-container', iElement))(scope);
                        } else {
                            $('.editable-input-container', iElement).find('input').attr('ng-model', iAttrs['ngModel']);
                            $compile($('.editable-input-container', iElement))(scope);
                        }
                        if($viewingReplacement.length) {
                            $('.editable-view-container', iElement).html($viewingReplacement.html());
                            $('.editable-view-container', iElement).append($viewingControls);
                            $compile($('.editable-view-container', iElement))(scope);
                        }
                        if($deletedReplacement.length) {
                            $('.editable-delete-container', iElement).html($deletedReplacement.html());
                            $('.editable-delete-container', iElement).append($deletedControls);
                        }
                    });

                    /**
                     * Deleted (Isolated Scope)
                     *
                     * Tracks if the user has clicked the delete button
                     * 
                     * @type {Boolean}
                     */
                    scope.deleted = false;

                    /**
                     * Editing (Isolated Scope)
                     *
                     * Tracks the state of the view
                     * 
                     * @type {Boolean}
                     */
                    scope.editing = false;

                    /**
                     * Initial Loader
                     *
                     * Run once after ctrl is loaded
                     * 
                     * @return {[type]} [description]
                     */
                    var unbindWatcher = scope.$watch(function() { return ctrl.$modelValue; }, function(newVal, oldVal) {
                        if(typeof ctrl.$modelValue !== 'undefined') {
                            scope.value = ctrl.$modelValue;
                            scope.editing = ctrl.$modelValue ? false : true;
                            unbindWatcher();
                        }
                    });

                };
            }
        };
    }
]);
规格 最后失败了

describe('Editable Directive', function() {

    // Keep references to element and scope so that they are available to all tests
    var element, scope, ctrl;

    beforeEach(module('ltAccountApp'));

    beforeEach(module('templates'));

    beforeEach(inject(function ($rootScope, $compile) {

        var linkFn, el;

        // scope = $rootScope;
        scope = $rootScope.$new();

        scope.testValue = 'xxx';

        el = angular.element('\
            <div editable="" ng-model="testValue"></div>\
        ');

        // The $compile method returns the directive's link function
        linkFn = $compile(el);

        // The link function returns the resulting DOM object
        element = linkFn(scope);

        element.scope().$apply();

        ctrl = element.controller('ngModel');

    }));

    it('should assign input value to scope value', function() {
        expect(element.find('input').val()).toEqual(scope.testValue);
    });

    it('should have access to parent scope variable passed into directive', function() {
        expect(ctrl.$viewValue).toEqual(scope.testValue);
        expect(ctrl.$modelValue).toEqual(scope.testValue);
    });

    it('should manage state editing correctly', function() {
        expect(element.scope().editing).toBe(false);
        element.scope().edit();
        expect(element.scope().editing).toBe(true);
    });

    it('should manage state deleted correctly', function() {
        expect(element.scope().deleted).toBe(false);
        element.scope()['delete']();
        expect(element.scope().deleted).toBe(true);
    });

    it('should be able to modify parent scope variable passed into directive', function() {
        // Not sure what this does, added from referenced SO question
        // spyOn(scope, '$apply').andCallThrough();

        var newValue = 'yyy';

        element.scope().edit();

        element.find('input').val(newValue);
        element.find('input').trigger('input');

        element.scope().ok();

        expect(ctrl.$viewValue).toEqual(newValue);
        expect(ctrl.$modelValue).toEqual(newValue);
        expect(element.scope().value).toEqual(newValue);

        expect(scope.$apply).toHaveBeenCalled();

        expect(scope.testValue).toEqual(newValue); // <-fails
    });
});
description('可编辑指令',函数()){
//保留对元素和范围的引用,以便所有测试都可以使用它们
var元素,作用域,ctrl;
在每个模块之前(模块('ltAccountApp');
每个之前(模块(“模板”);
beforeach(注入(函数($rootScope,$compile){
var linkFn,el;
//scope=$rootScope;
scope=$rootScope.$new();
scope.testValue='xxx';
el=角度。元素('\
\
');
//$compile方法返回指令的链接函数
linkFn=$compile(el);
//link函数返回生成的DOM对象
元素=linkFn(范围);
element.scope().$apply();
ctrl=element.controller('ngModel');
}));
它('应将输入值分配给范围值',函数(){
expect(element.find('input').val()).toEqual(scope.testValue);
});
它('应该有权访问传递到指令的父范围变量',函数(){
expect(ctrl.$viewValue).toEqual(scope.testValue);
expect(ctrl.$modelValue).toEqual(scope.testValue);
});
它('应正确管理状态编辑',函数(){
expect(element.scope().editing).toBe(false);
element.scope().edit();
expect(element.scope().editing).toBe(true);
});
它('应正确管理已删除的状态',函数(){
expect(element.scope().deleted).toBe(false);
element.scope()['delete']();
expect(element.scope().deleted).toBe(true);
});
它('应该能够修改传递到指令中的父范围变量',函数(){
//不确定这是做什么的,从引用的SO问题中添加
//spyOn(作用域“$apply”).andCallThrough();
var newValue='yyy';
element.scope().edit();
元素.find('input').val(newValue);
元素。查找('input')。触发器('input');
element.scope().ok();
expect(ctrl.$viewValue).toEqual(newValue);
expect(ctrl.$modelValue).toEqual(newValue);
expect(element.scope().value).toEqual(newValue);
expect(scope.$apply).tohavebeencall();

expect(scope.testValue).toEqual(newValue);//假设您必须将输入字段的值更新为“kasrak”。尝试如下操作:

var elm = element.find("input");
elm.val('kasrak');
elm.trigger($sniffer.hasEvent('input') ? 'input' : 'change');
$scope.$digest()
键是$sniffer服务的第三行。我在AngularUI的引导测试中发现了这一点


下面是测试规范中函数的链接:

我开始认为
scope.testValue
应该等于
newValue
的期望实际上是错误的。谢谢你,这个嗅探器提示救了我!