Mocking file uploads with file input elements is not straight forward as mocking other HTML elements while writing test cases. Why and how do we do that?
<input type="file" id="file-upload" onchange="doSomething" />
The file input elements have FileList object as its value. The FileList is nothing but a collection of File objects. The FileList object is read-only and we cannot construct custom FileList since it has no implementation of its constructor.
However, there is a way to construct them using the DataTransfer object.
DataTransfer object is responsible for holding the file objects in FileList during files drag & drop. We are gonna bypass the DataTransfer event's file addition methods to construct a FileList with our mocked files.
Let's create one,
const dt = () => new DataTransfer() || new ClipboardEvent('').clipboardData;
If the browser didn't support constructing a new DataTransfer, let's get the DataTransfer object from the ClipboardEvent (mock's file copy-paste) alternatively.
let's create a blob to construct a file object.
let fileString = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==';
(or)
let fileString = 'https://some-image-url.png';
let blob = await fetch(fileString).then(res => {
return res.blob();
});
And now file object,
let file = new File([blob], "sample.jpg", { type: 'image/png'})
will add the file object to the DataTransfer,
let dt = dt();
dt.items.add(file);
and it's time to add the FileList to the file input element
let $fileElement = document.getElementById('file-upload');
$fileElement.files = dt.files;
🎉 Yay! The files have been added to the file element and now let's emit the change event so that your UI can respond to the file upload.
let changeEvent = new Event('change');
$fileElement.dispatchEvent(changeEvent);
To ease this, I have created a test helper util to fill files to the file input element.
await fillInFIle('#file-upload') ✅
Check the GitHub repo for more details on the util:
Top comments (1)
DataTransfer object is not defined in Jest (jsdom). So, how to use it in this case?