4

几周前我进入了 JavaScript 的世界。我使用 Angular,并使用 Karma 和 Jasmine 测试我的代码。我有一个角度指令,我无法测试。

<input>我有一个与box一起使用的 angular 指令。该指令修改输入框,因此它只接受数字作为输入。这是代码的简化版本:

var testDirective = angular.module('testDirectiveApp', []);

testDirective.directive('numberOnly', function() {
    return {
      restrict: 'A',
      link: function (scope, element) {
        element.on('keydown', function (event) {
          var k = event.keyCode;
          if (48 <= k && k <= 57) {
            return true;
          }
          event.preventDefault();
          return false;
        });
      }
    };
  });

我会像这样在 html 中使用它:

<div>
    Numbers only: <input number-only ng-required="true" 
                  ng-model="myNumber" type="text" maxlength="3" 
                  placeholder="NNN">
</div>

我想测试该指令是否正确连接,并成功过滤掉非数字输入。如果我输入“a1b2c3”,输入框应该有“123”。

我尝试了许多不同的方法来将字符串输入到输入框并在之后检查一个值(输入框、角度模型等),但到目前为止,它们都没有奏效。

以下测试是我多次试验的一个例子:

describe('numberOnly', function() {
  'use strict';
  var scope, element;

  beforeEach(module('testDirectiveApp'));

  beforeEach(inject(function($compile, $rootScope) {
    scope = $rootScope.$new();
    scope.testInput = "";
    element = angular.element('<input number-only ng-model="testInput" type="text">');
    $compile(element)(scope);
    scope.$digest();
  }));

  it('should accept number input', function() {

    triggerKeyDown(element, 49);

    expect(scope.testInput).toBe("1");
  });

  var triggerKeyDown = function (element, keyCode) {
    var e = $.Event("keydown");
    e.which = keyCode;
    e.keyCode = keyCode;

    $(element).trigger(e);
  };
});

我什至尝试编写 e2e 测试来模拟用户输入。我还尝试从 HTML 元素中提取我的事件处理函数,并对函数进行单元测试。到目前为止都没有工作。

我应该如何最好地测试我的角度指令?

4

1 回答 1

0

在您的测试中,您实际上可以注入指令定义对象 (DDO),然后直接调用链接函数,而无需实际制作元素。

Angular 允许添加具有相同名称但具有不同优先级的指令。Angular 以数组的形式创建指令的可注入对象(因为具有多个优先级)。假设您只声明一次指令,我们可以假设您的 DDO 是数组中的第一个。

此代码未经测试,但应该可以帮助您完成大部分工作。

describe('numberOnly', function() {
  var scope, linkFunction;

  beforeEach(module('testDirectiveApp'));

  beforeEach(inject(function($compile, $rootScope, numberOnlyDirective) {
    scope = $rootScope.$new();
     //get the link function
     linkFunction = numberOnlyDirective[0].link;
   });

it('calls the event', function(){
    //make a mock element that has the 'on' function. 
    var onCallback;
    var mockElement = {
        on: function(eventName, cb){
          expect(eventName).toEqual("keydown");
           //save the callback so we can call it in our test
           onCallback = cb;
        }
    };

    linkFunction(scope, mockElement);
    var preventDefaultWasCalled = false;

    var mockEvent = {
        which: 1,
        keyCode: 1,
        preventDefault: function(){
           preventDefaultWasCalled = true;
        }
    };
    //trigger the 'keydown' event by calling the callback
    onCallback(mockEvent);
    expect(preventDefaultWasCalled).toEqual(true);
});
于 2016-05-20T13:04:23.037 回答