Selenium:从文件系统拖放到WebDriver
本文关键字:WebDriver 拖放 文件系统 Selenium | 更新日期: 2023-09-27 18:01:14
我必须测试一个web应用程序,该应用程序包含用于从本地文件系统上传文件的拖放区域。我的测试环境是基于C#的。
对于自动化测试,我使用了Selenium,但不可能从文件系统中拖动文件。上传区域是div
标签(没有input
标签(。那么,最好的方法是什么呢?AutoIt(是否可以放在web浏览器中(?Sikuli?
单独使用硒是可能的,但这并不简单。它需要在页面中注入一个新的INPUT
元素,以便通过SendKeys
接收文件。然后,脚本需要通过向目标区域发送dragenter
、dragover
、drop
事件来模拟丢弃。
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
前面的答案是正确的,与Chrome驱动程序完美配合,但Mozilla Gecko驱动程序可能存在问题,它会抛出org.openqa.selenium.ElementNotVisibleException
为了避免这种情况,请删除input.style.display = 'none';
如果需要使其消失,可以使用input.style.opacity = 0;
。
您可以使用JSExecutor:
public void dropFile(File filePath, WebElement target, int offsetX, int offsetY) {
if (!filePath.exists())
throw new WebDriverException("File not found: " + filePath.toString());
JavascriptExecutor jse = (JavascriptExecutor) driver;
String JS_DROP_FILE =
"var target = arguments[0]," +
" offsetX = arguments[1]," +
" offsetY = arguments[2]," +
" document = target.ownerDocument || document," +
" window = document.defaultView || window;" +
"" +
"var input = document.createElement('INPUT');" +
"input.type = 'file';" +
"input.style.display = 'none';" +
"input.onchange = function () {" +
" var rect = target.getBoundingClientRect()," +
" x = rect.left + (offsetX || (rect.width >> 1))," +
" y = rect.top + (offsetY || (rect.height >> 1))," +
" dataTransfer = { files: this.files };" +
"" +
" ['dragenter', 'dragover', 'drop'].forEach(function (name) {" +
" var evt = document.createEvent('MouseEvent');" +
" evt.initMouseEvent(name, !0, !0, window, 0, 0, 0, x, y, !1, !1, !1, !1, 0, null);" +
" evt.dataTransfer = dataTransfer;" +
" target.dispatchEvent(evt);" +
" });" +
"" +
" setTimeout(function () { document.body.removeChild(input); }, 25);" +
"};" +
"document.body.appendChild(input);" +
"return input;";
WebElement input = (WebElement) jse.executeScript(JS_DROP_FILE, target, offsetX, offsetY);
input.sendKeys(filePath.getAbsoluteFile().toString());
wait.until(ExpectedConditions.stalenessOf(input));
}
如果您正在使用硒化物:
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");
}
}