web-dev-qa-db-ja.com

セレン:ファイルシステムからWebDriverへのドラッグアンドドロップ?

ローカルファイルシステムからファイルをアップロードするためのドラッグアンドドロップ領域を含むWebアプリケーションをテストする必要があります。私のテスト環境はC#に基づいています。

自動テストではSeleniumを使用しましたが、ファイルシステムからファイルをドラッグすることはできません。アップロード領域はdivタグです(inputタグなし)。それを行うための最良の方法は何ですか? AutoIt(Webブラウザーでドロップすることは可能ですか)?シクリ?

16
Markoo91

Seleniumだけでも可能ですが、簡単ではありません。 INPUTを介してファイルを受け取るには、ページに新しいSendKeys要素を挿入する必要があります。次に、スクリプトはdragenterdragoverdropイベントをターゲット領域に送信して、ドロップをシミュレートする必要があります。

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);
}

出典: https://Gist.github.com/florentbr/349b1ab024ca9f3de56e6bf8af2ac69e

19
Florent B.

以前の答えは正解で、Chromeドライバーで完全に動作しますが、Mozilla Geckoドライバーで問題が発生する可能性があり、org.openqa.Selenium.ElementNotVisibleExceptionがスローされます

これを回避するには、input.style.display = 'none';を削除します

非表示にする必要がある場合は、input.style.opacity = 0;を使用できます。

6

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");
    }
}
0
Michael Dally