Its been a few years since the last response but I will add my own for those trying to use react dropzone with selenium, robot framework, or similar. The accepted answer may still work with pure selenium in your case, but as I am using robot framework with a non-standard library, my answer may not be universal. It is very slightly off topic but as I referenced this for creating my own keyword I hope it helps.
In my case I am using Qweb which required some additional setup such as getting the library instance and the webElement.
from robot.libraries.BuiltIn import BuiltIn
JS_DROP_FILE = """
var target = arguments[0],
offsetX = arguments[1],
offsetY = arguments[2],
// I did not need to fetch the document separately, it was already accessible in my case.
window = document.defaultView;
var input = document.createElement('INPUT');
input.type = 'file';
target.appendChild(input);
input.onchange = function () {
var rect = target.getBoundingClientRect(),
x = rect.left + (offsetX || (rect.width / 2)),
y = rect.top + (offsetY || (rect.height / 2));
var dataTransfer = new DataTransfer();
for (var i = 0; i < this.files.length; i++) {
dataTransfer.items.add(this.files[i]);
}
['dragenter', 'dragover', 'drop'].forEach(function (name) {
var evt = new MouseEvent(name, {
bubbles: true,
cancelable: true,
clientX: x,
clientY: y,
dataTransfer: dataTransfer
});
target.dispatchEvent(evt);
});
var fileDropEvent = new CustomEvent("file-drop", {
bubbles: true,
detail: { dataTransfer: dataTransfer }
});
target.dispatchEvent(fileDropEvent);
setTimeout(function () { target.removeChild(input); }, 25);
};
return input; // Return the input element
// # debugging: console.log(var) prints to chrome console
"""
def drag_and_drop_file(drop_target, path):
qweb = BuiltIn().get_library_instance('Qweb')
driver = qweb.return_browser() # debug: expect <selenium.webdriver.chrome.webdriver.WebDriver (session="alphabet-soup")>
# for selenium library, you will use a something along these lines
# selib = BuiltIn().get_library_instance("SeleniumLibrary")
# driver = selib.driver
# element = selib.get_webelement(drop_target)
element = qweb.get_webelement(drop_target)
if isinstance(element, list):
element = element[0] # debug: expect <selenium.webdriver.remote.webelement.WebElement (session="alphabet-soup", element="longer-alphabet-soup")>
file_input = driver.execute_script(JS_DROP_FILE, element, 0, 0)
file_input.send_keys(path)
# debugging: Builtin().log_to_console(var) prints to terminal
Some notable changes: new DataTransfer() and new MouseEvent() are more modern ways to handle these actions in chromium.
Other considerations: in my case the element is attached to the target vs the body, this makes debugging a little easier. You can still use body.appendChild and body.removeChild if you want to.
Working with react: You will preferably need some access to the react code in question, at least an ability to work with a developer, as the code will need to have an event listener. fileDropEvent is dispatched to the target, and thus the react code will need to have a useEffect() that will check for a target, and add an event listener for "file-drop" to it. This isn't the ideal case as you should not have to modify code much for QA purposes, but react-dropzone is a bit more difficult with automated testing.
const handlePhotosUpload = useCallback(
// Your photo upload logic here
);
useEffect(() => {
const target = document.getElementById("upload-photos");
const handleFileDrop = (event: any) => {
// Prevent default browser handling
event.preventDefault();
if (event.detail?.dataTransfer?.files) {
handlePhotosUpload(Array.from(event.detail.dataTransfer.files));
}
};
if (target) {
target.addEventListener("file-drop", handleFileDrop);
}
return () => {
if (target) {
target.removeEventListener("file-drop", handleFileDrop);
}
};
}, [handlePhotosUpload]);
Usage in robot framework:
*** Settings ***
Library QWeb # Or SeleniumLibrary or Browser, whichever you use
Library drag-n-drop.py
*** Keywords ***
Upload Photo
[Arguments] ${photo}
[Documentation] Executes a custom script to drag and drop a photo into the dropzone.
Scroll to //*[@id\="upload-photos"].
# note: Qweb requires escape chars in xpath.
# In selenium, xpath://div[@id="example"] or id:example may work.
# I did not test this in selenium.
Drag And Drop File //*[@id\="upload-photos"] ${EXECDIR}/files/images/${photo}
Sleep 2s # wait for photo to upload
*** Test Cases ***
Upload A Photo
Upload Photo my_picture.jpeg
explorer.execan be automated using pywinauto. My student wrote an example that drags-n-drops the file fromexplorer.exeto Chrome (Google Disk). Can it be helpful?