Mock file input for unit test
Solution 1
Alright I find a solution. You can't create a faked native event with files and for security reasons that's a good thing. But in my case the solution looks like this:
it('should create a fileReader', function(){
var onChangeCallback;
spyOn(jQuery.fn, 'on').and.callFake(function(eventName, callback){
if(eventName === 'change'){
onChangeCallback = callback;
}
});
spyOn(window, 'FileReader').and.returnValue({
addEventListener: function(){},
readAsDataURL: function(){}
});
onChangeCallback({target:{files:[1,2,3]}});
expect(window.FileReader).toHaveBeenCalled();
});
Solution 2
this article may helps
http://nerds.intuo.io/2016/05/12/mocking-file-uploads-in-javascript.html
function fillInFileInput(selector, file) {
// Get the input
let input = jQuery(selector);
// Get out file options
let { name, type, content } = file;
// Create a custom event for change and inject target
let event = jQuery.Event('change', {
target: {
files: [{
name: name, type: type
}]
}
});
// Stub readAsDataURL function
let stub = sinon.stub(FileReader.prototype, 'readAsDataURL', function() {
this.onload({ target: { result: content }});
});
// Trigger event
input.trigger(event);
// We don't want FileReader to be stubbed for all eternity
stub.restore();
}
Solution 3
While you can't assign a value to fileInput.files
, you can replace the property with your own, which accomplishes the same thing:
it('should create a fileReader', () => {
const fileInput = $('input[type=file]');
const fileInputElement = fileInput.get(0);
Object.defineProperty(fileInputElement, 'files', {
value: [{name: 'file.txt'}],
writable: false,
});
fileInput.trigger('input').trigger('change');
// expect outputs...
});
This is a bit better than creating your own event object, since it simulates the real environment a little more closely.
![Jakob](https://i.stack.imgur.com/5qdM8.jpg?s=256&g=1)
Jakob
Updated on June 05, 2022Comments
-
Jakob about 2 years
I got something like these lines of code:
jQuery('.js-img-input').on('change', handleNewFiles); var handleNewFiles = function(event) { var fileList = event.target.files; loadFileList(fileList); }; var loadFileList = function(fileList) { jQuery(fileList).each(function(key, file) { readFileAsync(file); }); } var readFileAsync = function(file) { var fileReader = new FileReader(); fileReader.addEventListener("load", function(event) { file.result = event.target.result; saveFile(file); }); fileReader.readAsDataURL(file); };
All of the methods are private inside a jQuery-function and I don't whant to make "handleNewFiles" public just for testing purpose.
I would love to test these lines with something like this:it('should create a fileReader', function(){ spyOn(window, 'FileReader').and.returnValue({ addEventListener: function(){}, readAsDataURL: function(){} }); jQuery('.js-img-input').trigger('change'); expect(window.FileReader).toHaveBeenCalled(); });
But how did I get some dummy data into event.target.files?