javascript - 如何提供模拟文件来更改 <input type ='file' > 的事件以进行单元测试

标签 javascript angularjs unit-testing jasmine

我在单元测试中遇到困难,我想验证文件的处理,通常会通过<input type='file'>在 View 中选择该文件。 .

在我的 AngularJS 应用程序的 Controller 部分中,文件在输入的更改事件内进行处理,如下所示:

//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在我的单元测试中包含我的模拟数据而不是用户选择的文件。我意识到我无法实例化 FileListFile我自己的对象,这将是浏览器正在使用的相应对象。所以我将模拟 FileList 分配给输入的 files属性并手动触发更改事件:

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!');
    });

不幸的是,这会导致 Controller 中出现以下错误,表明此尝试失败,因为文件根本没有分配给输入元素:

TypeError: 'undefined' is not an object (evaluating 'evt.target.files')

我已经发现input.files出于安全原因,该属性是只读。因此,我开始了另一种方法,通过发送自定义更改来提供文件属性,但仍然没有成功。

长话短说:我渴望学习一个可行的解决方案或任何有关如何处理此测试用例的最佳实践。

最佳答案

更新:感谢@PeteBD,

自 angularjs 版本 1.2.22 起,jqLit​​e 现在支持将自定义事件对象传递给 triggerHandler()。请参阅:d262378b

<小时/>

如果您仅使用 jqLit​​e

triggerHandler() 永远不会工作,因为它将向处理程序传递一个虚拟事件对象。

虚拟事件对象如下所示(复制自 jqLite.js#L962 )

{
  preventDefault: noop,
  stopPropagation: noop
}

如您所见,它甚至没有 target 属性。

如果您使用的是 jQuery

您可以使用自定义事件对象触发事件,如下所示:

input.triggerHandler({
  type: 'change',
  target: {
    files: fileList
  }
});

并且evt.target.files将是您期望的fileList

希望这有帮助。

关于javascript - 如何提供模拟文件来更改 &lt;input type ='file' > 的事件以进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25097738/

相关文章:

angularjs - Q : AngularJS, 如何将图像放入背景 div 中?

javascript - qunit 和 jquery 未捕获的异常

php - 模拟对象和仅设置值有什么区别

java - 瓦丁 : Call a custom JavaScript function

javascript - 实例属性与原型(prototype)属性

javascript - 如何将 JavaScript 添加到自定义元素?

c# - 匿名类型的 default(T) 行为

javascript - 谁能解释一下Underscore在_.template中的预编译?

javascript - angularjs如何通过下划线或其他任何方式从数组中删除对象

javascript - 来自 ng-model 的 Controller 中的未定义参数