在角度形式指令的单元测试中设置视图值输入字段

Posted

技术标签:

【中文标题】在角度形式指令的单元测试中设置视图值输入字段【英文标题】:Setting view value an input field in a unit test of an angular form directive 【发布时间】:2014-12-09 22:48:46 【问题描述】:

我有一个构建表单的指令:

app.directive('config', function() 
  return 
    restrict: 'E',
    scope: 
      data: '='
    ,
    template: '<form name="configForm">' +
      '<input type="number" max="10" ng-model="config.item" name="configItem"/>' +
      '<div class="form-error" ng-show="configForm.$error.max">Error</div>' + 
      '</form>',
    controller: 'ConfigDirectiveController',
  ;
);

我想要做的是通过单元测试验证在给定一些输入的情况下会显示错误消息。使用 Angular 1.2,我可以修改 $scope.config.item,它会更新视图值并显示错误。

据我所知,对于 angular 1.3,如果模型未通过验证,则视图值不会更新...所以我需要修改视图值以确保显示错误消息。

如何访问“configItem”输入,以便设置视图值以确保显示错误消息?

已编辑以显示单元测试

我看到该值设置正确,但错误仍然有一个 ng-hide 应用于标签。当我查看页面并手动更改输入值时,ng-hide 将被移除,如果我输入大于 10 的值,则会显示错误。

  beforeEach(inject(function($compile, $rootScope) 
      element = angular.element('<config data="myData"></config>');
      $scope = $rootScope.$new();
      $scope.myData = ;
      element = $compile(element)($scope);
    ));

    it('should warn that we have a large number', function() 
      var input = element.find('[name="configItem"]')[0];
      $scope.$apply(function() 
        angular.element(input).val('9000000001');
      );
      errors = element.find('[class="form-error ng-binding"]');
      expect(errors.length).toBe(1);
    )

【问题讨论】:

【参考方案1】:

如果您将 Angular 与 jQuery 一起使用,则前面的答案是正确的,但对于没有 jQuery 的 Angular(使用 jqlite),您可以改用 triggerHandler(完整 API 参见 here)

it('foos to the bar', function() 
  el.val('Foo').triggerHandler('input');

  // Assuming el is bound to scope.something using ng-model ...
  expect(scope.something).toBe('Foo');
);

【讨论】:

【参考方案2】:

以下是我对基于输入的指令进行单元测试的方式(为清楚起见,省略了很多代码!)您所关注的重要行是:

angular.element(dirElementInput).val('Some text').trigger('input');

这是完整的单元测试:

  it('Should show a red cross when invalid', function () 

    dirElement = angular.element('<ng-form name="dummyForm"><my-text-entry ng-model="name"></my-text-entry></ng-form>');

    compile(dirElement)(scope);
    scope.$digest();

    // Find the input control: 
    var dirElementInput = dirElement.find('input');

    // Set some text!
    angular.element(dirElementInput).val('Some text').trigger('input');
    scope.$apply();

    // Check the outcome is what you expect! (in my case, that a specific class has been applied)
    expect(dirElementInput.hasClass('ng-valid')).toEqual(true);
  );

【讨论】:

我会将其标记为已回答,因为它确实让我中途了。它确实会修改输入元素,但不会触发验证。相反,它不会导致 configForm.$error.max 被标记为 true ......所以我的错误仍然隐藏。 这可能是因为您没有使用指令的编译输出。在您的示例中,您使用编译的输出(var 元素)覆盖指令输入,有时不是(dirElement)。如果你使用编译的结果应该让你更接近角度的实际形式行为。 n.b 这个例子利用了.trigger(),它假设你使用 Angular 和 jQuery。如果您使用的是 jqlite 实现,则需要使用 angular.element(dirEelementInput)[0].dispatchEvent(new Event('input')); 之类的内容手动分派错误。 也可以是 `scope.configForm.configItem.$setViewValue("some value", true);范围.$apply(); ` 第二个参数触发处理程序 也很重要scope.$apply()!

以上是关于在角度形式指令的单元测试中设置视图值输入字段的主要内容,如果未能解决你的问题,请参考以下文章

在集合视图单元格中设置文本时出错

在Laravel 4单元测试中,如何在请求中设置cookie?

在视图控制器中设置表格视图

在单元测试中设置 HttpContext.Current.Session

在 redux 形式的文本字段中设置初始值

如何模拟具有要求字段的角度指令