Karma单元测试带有关键事件处理程序的角度指令



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

我有一个角度指令,用于<input>框。该指令修改输入框,使其只接受数字作为输入。以下是代码的简化版本:

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元素中提取事件处理程序函数,并对该函数进行单元测试。到目前为止,没有一个奏效。

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

在测试中,您可以实际注入指令定义对象(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);
});

最新更新