如何在AngularJS指令测试中模拟模糊效果?

5

问题

我正在尝试测试一些指令(下面是两个指令的代码)。其中之一是“电子邮件”指令(在代码中称为“epost”(挪威语))。这个解决方案应该适用于所有指令,所以现在我只关注这一个。

技术:Angularjs,Jasmine,Requirejs,(grunt和karma在Chrome中运行)

该指令通过两种方式验证电子邮件地址;在upshift和模糊上。我可以轻松测试upshift,如下面的测试所示,但我不知道如何模拟模糊,使指令中的bind('blur')运行。

我做了什么

我尝试像这样捕获编译的元素:

elem    = angular.element(html);
element = $compile(elem)($scope);

在测试中,我尝试使用多种排列方式通过指令中绑定函数内的控制台日志来触发模糊效果,但以下任何一种方式都不起作用。

elem.trigger('blur');           
element.trigger('blur');
elem.triggerHandler('blur');
element.triggerHandler('blur');
element.blur();
elem.blur();

我基于这个链接中的注入和设置进行了操作:To test a custom validation angularjs directive AngularJS中的电子邮件指令包装在RequireJS中
define(function() {

var Directive = function() {

return {
  require: 'ngModel',
  link: function(scope, elem, attrs, ctrl) {
    var pattern = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/;

    elem.bind('blur', function() {
      scope.$apply(function () {
        if (!elem.val() || pattern.test(elem.val())) {
          ctrl.$setValidity('epost', true);
        } else {
          ctrl.$setValidity('epost', false);
        }
      });
    });

    ctrl.$parsers.unshift(function(viewValue) {
      if (pattern.test(viewValue)) {
        ctrl.$setValidity('epost', true);
        return viewValue;
      } else {
        return undefined;
      }
      });
    }
  };
};

return Directive;

});

测试(使用Jasmine和RequireJS)

define([
'Angular', 
'AngularMocks',
], function () {

describe('Directives', function () {

    var $scope;
    var form;

    beforeEach(module('common'));
    beforeEach(function () {

        var html = '<form name="form">';
        html += '<input type="text" id="epost" name="epost" epost="" ng-model="model.epost"/>';
        html += '</form>';

        inject(function ($compile, $rootScope) {
            $scope = $rootScope.$new();

            $scope.model = { 
                epost: null
            };

            // Compile the element, run digest cycle
            var elem = angular.element(html);
            $compile(elem)($scope);
            $scope.$digest();

            form = $scope.form;

        });
    }); 

    describe('(epost) Given an input field hooked up with the email directive', function () {

        var validEmail = 'a@b.no';
        var invalidEmail = 'asdf@asdf';

        it('should bind data to model and be valid when email is valid on upshift', function () {
            form.epost.$setViewValue(validEmail);
            expect($scope.model.epost).toBe(validEmail);
            expect(form.epost.$valid).toBe(true);
        });
        });
    });
});
2个回答

8

通过断点调试,我已经找出了自己的错误。

使用问题开头描述的方法所得到的“element”项实际上并不是指令本身。它是一个包装表单和指令的对象。

就像这样:

{ 0:   // The form
  { 0: // The directive (input element)
    {  
    }
  }
}

为了在指令本身上实际模拟模糊效果,我做了类似于这样的事情。
var directiveElement = $(element[0][0]);
directiveElement.blur();

在获取我想要的元素并将其包装为jQuery对象之后(可能是可选的),它就像魔法一样起作用了。然后我使用了与测试中提出的方法类似的方法,使用$setViewValue并像这样检查模型值。
form.epost.$setViewValue('a@b.no');
directiveElement.blur();
expect($scope.model.epost).toBe('a@b.no');
expect($scope.form.epost.$valid).toBeTruthy();

希望这对于其他试图理解指令测试的人有所帮助。

请问您能否将您的指令测试以最终形式发布?如果有一个fiddle就更好了,但如果您愿意,也可以更新您的答案...我遇到了与您相同的问题,但是您的解决方案对我不起作用(似乎blur()调用没有触发指令执行...)。 - MarcoS
@MarcoS 很抱歉,我无法再访问这段代码,因为它是客户的。祝你好运解决问题。 - lizter
那个$(element[0][0])是关键,简单的element[0][0].blur()是行不通的。非常感谢。 - Tsagana Nokhaeva

0

我也遇到了类似的问题,让我感到困惑。我的解决方案是使用JQuery获取输入,然后使用angular.element(input).triggerHandler('blur')使其正常工作。这对我来说很奇怪,因为我在点击事件中不必这样做。

spyOn(controller, 'setRevenueIsInvalid');
var sugarRow = $(element).find('tr#ve_id_5')[0];
var amount = $(sugarRow).find('input.amount')[0];
angular.element(amount).triggerHandler('blur');
expect(controller.setRevenueIsInvalid).toHaveBeenCalled();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接