Selenium: Drag and Drop from file system to WebDriver?
It's possible with Selenium alone, but it's not simple. It requires to inject a new INPUT
element in the page to receive the file through SendKeys
. Then, the script needs to simulate the drop by sending the dragenter
, dragover
, drop
events to the targeted area.
static void Main(string[] args){ var driver = new ChromeDriver(); driver.Url = "https://react-dropzone.js.org/"; IWebElement droparea = driver.FindElementByCssSelector("[data-preview='Basic example'] [style]"); DropFile(droparea, @"C:\Users\florent\Desktop\capture.png"); driver.Quit();}const string JS_DROP_FILE = "for(var b=arguments[0],k=arguments[1],l=arguments[2],c=b.ownerDocument,m=0;;){var e=b.getBoundingClientRect(),g=e.left+(k||e.width/2),h=e.top+(l||e.height/2),f=c.elementFromPoint(g,h);if(f&&b.contains(f))break;if(1<++m)throw b=Error('Element not interractable'),b.code=15,b;b.scrollIntoView({behavior:'instant',block:'center',inline:'center'})}var a=c.createElement('INPUT');a.setAttribute('type','file');a.setAttribute('style','position:fixed;z-index:2147483647;left:0;top:0;');a.onchange=function(){var b={effectAllowed:'all',dropEffect:'none',types:['Files'],files:this.files,setData:function(){},getData:function(){},clearData:function(){},setDragImage:function(){}};window.DataTransferItemList&&(b.items=Object.setPrototypeOf([Object.setPrototypeOf({kind:'file',type:this.files[0].type,file:this.files[0],getAsFile:function(){return this.file},getAsString:function(b){var a=new FileReader;a.onload=function(a){b(a.target.result)};a.readAsText(this.file)}},DataTransferItem.prototype)],DataTransferItemList.prototype));Object.setPrototypeOf(b,DataTransfer.prototype);['dragenter','dragover','drop'].forEach(function(a){var d=c.createEvent('DragEvent');d.initMouseEvent(a,!0,!0,c.defaultView,0,0,0,g,h,!1,!1,!1,!1,0,null);Object.setPrototypeOf(d,null);d.dataTransfer=b;Object.setPrototypeOf(d,DragEvent.prototype);f.dispatchEvent(d)});a.parentElement.removeChild(a)};c.documentElement.appendChild(a);a.getBoundingClientRect();return a;";static void DropFile(IWebElement target, string filePath, double offsetX = 0, double offsetY = 0){ if (!File.Exists(filePath)) throw new FileNotFoundException(filePath); IWebDriver driver = ((RemoteWebElement)target).WrappedDriver; IJavaScriptExecutor jse = (IJavaScriptExecutor)driver; IWebElement input = (IWebElement)jse.ExecuteScript(JS_DROP_FILE, target, offsetX, offsetY); input.SendKeys(filePath);}
Source: https://gist.github.com/florentbr/349b1ab024ca9f3de56e6bf8af2ac69e
The previous answer is correct and works perfectly with the Chrome driver, however might have problems with Mozilla Gecko driver, which throws org.openqa.selenium.ElementNotVisibleException
In order to avoid that, remove input.style.display = 'none';
You can use input.style.opacity = 0;
if you need to make it disappear.
If you're using Selenide:
public static void dragAndDropFileUpload(File file, SelenideElement target) throws IOException { String inputId = "seleniumDragAndDropInput"; // Create the FileList executeJavaScript(inputId + "_files = [];"); executeJavaScript(inputId + "_files.push(new File([new Blob(['" + file.getAbsolutePath() + "'], {type: '" + Files.probeContentType(file.toPath()) + "'})], '" + file.getName() + "'));"); String targetId = target.getAttribute("id"); // Add an id if the target doesn't have one if (targetId == null || targetId.isEmpty()) { targetId = "seleniumDragAndDropInput_target"; executeJavaScript("sId=function(e, i){e.id = i;};sId(arguments[0], arguments[1]);", target, targetId); } // Add the item function the the FileList // Create the drop event and dispatch it on the target String initEventJS = inputId + "_files.item = function (i) {return this[i];};" + "var eve=document.createEvent(\"HTMLEvents\");" + "eve.initEvent(\"drop\", true, true);" + "eve.dataTransfer = {files:seleniumDragAndDropInput_files};" + "eve.preventDefault = function () {};" + "eve.type = \"drop\";" + "document.getElementById('" + targetId + "').dispatchEvent(eve);"; executeJavaScript(initEventJS); if (targetId == "seleniumDragAndDropInput_target") { executeJavaScript("document.getElementById('seleniumDragAndDropInput_target').id = null"); }}