Search code examples
c#seleniumui-automation

Selenium: Drag and Drop from file system to WebDriver?


I have to test a web-application which contains a drag and drop area for uploading files from the local file system. My test environment is based on C#.

For the automation testing I have used Selenium, but it is not possible to drag files from the file system. The upload area is a div tag (no input tag). So what's the best way to do it? AutoIt (is it possible to drop in a web browser)? Sikuli?


Solution

  • 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