Mob*_*ent 19 javascript unit-testing jasmine angularjs
我在单元测试中遇到困难,我想在其中验证文件的处理,通常在视图中选择<input type='file'>.
在我的AngularJS应用程序的控制器部分,文件在输入的change事件中处理,如下所示:
//bind the change event of the file input and process the selected file
inputElement.on("change", function (evt) {
var fileList = evt.target.files;
var selectedFile = fileList[0];
if (selectedFile.size > 500000) {
alert('File too big!');
// ...
Run Code Online (Sandbox Code Playgroud)
我想evt.target.files在我的单元测试中包含我的模拟数据而不是用户选择的文件.我意识到我不能自己实例化一个FileList和File对象,这将是浏览器正在使用的相应对象.所以我选择将一个模拟FileList分配给输入的files属性并手动触发change事件:
describe('document upload:', function () {
var input;
beforeEach(function () {
input = angular.element("<input type='file' id='file' accept='image/*'>");
spyOn(document, 'getElementById').andReturn(input);
createController();
});
it('should check file size of the selected file', function () {
var file = {
name: "test.png",
size: 500001,
type: "image/png"
};
var fileList = {
0: file,
length: 1,
item: function (index) { return file; }
};
input.files = fileList; // assign the mock files to the input element
input.triggerHandler("change"); // trigger the change event
expect(window.alert).toHaveBeenCalledWith('File too big!');
});
Run Code Online (Sandbox Code Playgroud)
不幸的是,这会导致控制器中出现以下错误,表明此尝试失败,因为文件根本没有分配给输入元素:
TypeError:'undefined'不是对象(评估'evt.target.files')
我已经发现该input.files属性是出于安全原因的只读属性.所以我开始采用另一种方法,通过调度提供文件属性的自定义更改,但仍然没有成功.
长话短说:我渴望学习如何处理这个测试用例的工作解决方案或任何最佳实践.
run*_*arm 11
更新:感谢@PeteBD,
从angularjs版本1.2.22开始,jqLite现在支持将自定义事件对象传递给triggerHandler().见:d262378b
如果你只使用jqLite,
将triggerHandler()永远不会工作,因为它会通过一个虚拟事件对象来处理.
虚拟事件对象看起来像这样(从jqLite.js复制#L962)
{
preventDefault: noop,
stopPropagation: noop
}
Run Code Online (Sandbox Code Playgroud)
如你所见,它甚至没有target财产.
如果你使用的是jQuery,
您可以使用如下自定义事件对象触发事件:
input.triggerHandler({
type: 'change',
target: {
files: fileList
}
});
Run Code Online (Sandbox Code Playgroud)
这evt.target.files将是fileList你所期待的.
希望这可以帮助.
让我们重新考虑AngularJS, DOM must be handled in a directive
我们不应该在控制器中处理DOM元素,即element.on('change', ..特别是为了测试目的.在控制器中,您与数据交谈,而不是与DOM交谈.
因此,那些onchange应该是如下的指令
<input type="file" name='file' ng-change="fileChanged()" /> <br/>
Run Code Online (Sandbox Code Playgroud)
然而,遗憾的是,ng-change并不适用type="file".我不确定未来版本是否适用于此.我们仍然可以应用相同的方法.
<input type="file"
onchange="angular.element(this).scope().fileChanged(this.files)" />
Run Code Online (Sandbox Code Playgroud)
在控制器中,我们只是简单地定义一个方法
$scope.fileChanged = function(files) {
return files.0.length < 500000;
};
Run Code Online (Sandbox Code Playgroud)
现在,一切都只是一个正常的控制器测试.没有更多的处理angular.element,$compile,triggers等!:)
describe(‘MyCtrl’, function() {
it('does check files', inject(
function($rootScope, $controller) {
scope = $rootScope.new();
ctrl = $controller(‘UploadCtrl’, {‘$scope’: scope});
var files = { 0: {name:'foo', size: 500001} };
expect(scope.fileChanged(files)).toBe(true);
}
));
});
Run Code Online (Sandbox Code Playgroud)
http://plnkr.co/edit/1J7ETus0etBLO18FQDhK?p=preview
| 归档时间: |
|
| 查看次数: |
18258 次 |
| 最近记录: |