使用 Selenium 模拟将文件拖到上传元素上
Posted
技术标签:
【中文标题】使用 Selenium 模拟将文件拖到上传元素上【英文标题】:Using Selenium to imitate dragging a file onto an upload element 【发布时间】:2011-07-08 11:27:12 【问题描述】:我有一个网页,当您单击按钮时会打开一个 div。此 div 允许您将文件从桌面拖到其区域;然后文件被上传到服务器。我正在使用 Selenium 的 Ruby 实现。
通过在 Firefox 中使用 javascript 调试器,我可以看到一个名为“drop”的事件正在传递给一些 JavaScript 代码“handleFileDrop(event)”。我假设如果我要创建一个模拟事件并以某种方式触发它,我可以触发此代码。
如果发现interesting article 似乎为我指明了一个有希望的方向,但我仍然没有完全弄清楚。我可以使用 Selenium 的 get_eval 方法将 JavaScript 传递给页面。使用 this.browserbot 调用方法让我得到了我需要的元素。
所以:
-
如何构建文件对象
需要成为模拟下降的一部分
事件?
如何触发 drop 事件
这样它就会被捡起来,就好像我
在 div 中删除了一个文件?
【问题讨论】:
【参考方案1】:我发布了一个 RSpec 测试,该测试使用 Selenium webdriver 模拟文件拖放。 它使用 jQuery 来制作和触发一个虚假的 'drop' 事件。
此代码模拟单个文件的拖放。为简单起见,我删除了允许删除多个文件的代码。需要的话告诉我。
describe "when user drop files", :js => true do
before do
page.execute_script("seleniumUpload = window.$('<input/>').attr(id: 'seleniumUpload', type:'file').appendTo('body');")
attach_file('seleniumUpload', Rails.root + 'spec/support/pdffile/pdfTest.pdf')
# Trigger the drop event
page.execute_script("e = $.Event('drop'); e.originalEvent = dataTransfer : files : seleniumUpload.get(0).files ; $('#fileDropArea').trigger(e);")
end
it "should ..." do
should have_content '...'
end
P.S.:记得将#fileDropArea 替换为放置区域的ID。
附注:不要使用 evaluate_script 代替 execute_script,否则 selenium 会在评估复杂的 jQuery 对象时卡住!
更新: 我写了一个方法,你可以重用并做上面写的东西。
def drop_files files, drop_area_id
js_script = "fileList = Array();"
files.count.times do |i|
# Generate a fake input selector
page.execute_script("if ($('#seleniumUpload#i').length == 0) seleniumUpload#i = window.$('<input/>').attr(id: 'seleniumUpload#i', type:'file').appendTo('body'); ")
# Attach file to the fake input selector through Capybara
attach_file("seleniumUpload#i", files[i])
# Build up the fake js event
js_script = "#js_script fileList.push(seleniumUpload#i.get(0).files[0]);"
end
# Trigger the fake drop event
page.execute_script("#js_script e = $.Event('drop'); e.originalEvent = dataTransfer : files : fileList ; $('##drop_area_id').trigger(e);")
end
用法:
describe "when user drop files", :js => true do
before do
files = [ Rails.root + 'spec/support/pdffile/pdfTest1.pdf',
Rails.root + 'spec/support/pdffile/pdfTest2.pdf',
Rails.root + 'spec/support/pdffile/pdfTest3.pdf' ]
drop_files files, 'fileDropArea'
end
it "should ..." do
should have_content '...'
end
end
【讨论】:
这看起来不错——我没有在我当前的项目中使用 RSpec,所以如果其他人可以确认这在 cmets 中有效,那么我会接受这个答案。 在 rspec 中确认 - 完美运行!先生,你成就了我的一天! :) 感谢您 - 我已经成功翻译了代码,以便使用 C# 进行测试。 @Shmoopy 添加为下面的答案 :) 请注意,drop_area_id
是附加了 ondrop 事件处理程序的 html 元素。【参考方案2】:
根据@Shmoopy 的要求,这是@micred 提供的代码的C# 翻译
private void DropImage(string dropBoxId, string filePath)
var javascriptDriver = this.Driver as IJavaScriptExecutor;
var inputId = dropBoxId + "FileUpload";
// append input to HTML to add file path
javascriptDriver.ExecuteScript(inputId + " = window.$('<input id=\"" + inputId + "\"/>').attr(type:'file').appendTo('body');");
this.Driver.FindElement(By.Id(inputId)).SendKeys(filePath);
// fire mock event pointing to inserted file path
javascriptDriver.ExecuteScript("e = $.Event('drop'); e.originalEvent = dataTransfer : files : " + inputId + ".get(0).files ; $('#" + dropBoxId + "').trigger(e);");
【讨论】:
谢谢,这对我有帮助。虽然我收到了错误selenium Unexpected error. type property can't be changed
。通过将 $('<input id=\"" + inputId + "\"/>').attr(type:'file')
更改为 $('<input id=\"" + inputId + "\" type=\"file\" />')
来修复。【参考方案3】:
您可以使用 Blueduck Sda (http://sda.blueducktesting.com) 是一个实现了所有 selenium 功能的 OSS(它适用于 selenium RC),但它允许您自动执行 Windows 操作。所以你可以测试网络,并与操作系统交互。 因此,您可以进行测试,然后只需告诉鼠标单击元素并将其放到您想要的位置!
很好的测试!
【讨论】:
这看起来可能是一个选项,虽然我在 OSX 中工作,而不是 Windows。我也对在 JavaScript 上下文中与浏览器机器人交互和触发事件感到好奇。 在撰写本文时 blueducktesting.com 域名正在出售中。【参考方案4】:注意:您还应该添加
e.originalEvent.dataTransfer.types = [ 'Files' ];
【讨论】:
以上是关于使用 Selenium 模拟将文件拖到上传元素上的主要内容,如果未能解决你的问题,请参考以下文章
Python + Selenium + AutoIt 模拟键盘实现另存为上传下载操作详解
详解介绍Selenium常用API的使用--Java语言(完整版)
python使用selenium模拟点击网页实现自动导入上传文件功能