我在其中我想验证一个文件,这通常会在视图中通过选择的处理与单元测试的困难<输入类型='文件'>
。
I'm having difficulties with a unit test in which I want to verify the processing of a file, which would usually be selected in the view via <input type='file'>
.
在我AngularJS的控制器部分应用程序的文件是输入的变化事件中处理,像这样:
In the controller part of my AngularJS app the file is processed inside the input's change event like so:
//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!');
// ...
我想 evt.target.files
包含在我的单元测试用户选择的文件,而不是我的模拟数据。我意识到,我不能用自己实例化一个文件清单
和文件
对象,这将是根据对象的浏览器正在与。所以我分配一个模拟文件清单到输入的文件
财产和手动触发事件改变了:
I'd like evt.target.files
to contain my mock data instead of the user's selected file in my unit test. I realized that I can't instantiate a FileList
and File
object by myself, which would be the according objects the browser is working with. So I went with assigning a mock FileList to the input's files
property and triggering the change event manually:
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!');
});
不幸的是,这会导致在控制器以下错误,显示这尝试失败,因为文件没有分配给输入元件在所有的
Unfortunately, this causes the following error in the controller which shows that this attempt failed because the files were not assigned to the input element at all:
类型错误:未定义是不是(评估'evt.target.files')
我已经发现,在 input.files
属性的只读出于安全原因。所以,我派遣一个定制的变化,这将提供这些文件的属性,但还是没有成功开始了另一种方法。
I already found out that the input.files
property is read-only for security reasons. So I started another approach by dispatching a customized change which would provide the files property, but still without success.
所以长话短说:我很渴望了解一个有效的解决方案,或对如何处理这个测试用例的最佳做法
让我们重新思考AngularJS, DOM必须在一个指令进行处理
Let's rethink AngularJS, DOM must be handled in a directive
我们不应该与DOM元素在处理控制器,即 element.on('变',..
,特别是用于测试目的。在一个控制器,你说话数据,而不是DOM。
We should not deal with DOM element in a controller, i.e. element.on('change', ..
, especially for testing purpose. In a controller, You talk to data, not to DOM.
因此,那些的onchange
应该像一个指令以下
Thus, those onchange
should be a directive like the following
<input type="file" name='file' ng-change="fileChanged()" /> <br/>
然而,遗憾的是, NG-变化
不很好地工作类型=文件
。我不知道未来的版本适用于本与否。我们仍然可以申请,虽然同样的方法。
However, unfortunately, ng-change
does not work well with type="file"
. I am not sure that the future version works with this or not. We still can apply the same method though.
<input type="file"
onchange="angular.element(this).scope().fileChanged(this.files)" />
和控制器,我们只是简单地定义一个方法
and in the controller, we just simply define a method
$scope.fileChanged = function(files) {
return files.0.length < 500000;
};
现在,一切都只是一个正常的控制器测试。没有更多的 angular.element
, $处理编译
,触发
等! :)
Now, everything is just a normal controller test. No more dealing with angular.element
, $compile
, triggers
, etc.! :)
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);
}
));
});
http://plnkr.co/edit/1J7ETus0etBLO18FQDhK?p=$p$ PVIEW