javascript 使用 Selenium 模拟将文件拖到上传元素上

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5188240/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 16:18:30  来源:igfitidea点击:

Using Selenium to imitate dragging a file onto an upload element

javascriptrubyselenium

提问by Ben Flynn

I have a web page that opens a div when you click a button. This div allows you to drag a file from your desktop onto its area; the file then gets uploaded to the server. I'm working with the Ruby implementation of Selenium.

我有一个网页,当您单击按钮时会打开一个 div。此 div 允许您将文件从桌面拖到其区域;然后文件被上传到服务器。我正在使用 Selenium 的 Ruby 实现。

By using the JavaScript debugger in Firefox, I can see that an event called "drop" is being passed to some JavaScript code "handleFileDrop(event)". I presume that if I were to create a mock event and fire it somehow that I could trigger this code.

通过在 Firefox 中使用 JavaScript 调试器,我可以看到一个名为“drop”的事件正在传递给一些 JavaScript 代码“handleFileDrop(event)”。我认为如果我要创建一个模拟事件并以某种方式触发它,我可以触发此代码。

If found an interesting articlethat seemed to point me in a promising direction, but I'm still short of figuring it all out. I am able to pass JavaScript to the page using Selenium's get_eval method. Calling methods using this.browserbot is getting me the elements I need.

如果发现一篇有趣的文章似乎为我指明了一个有希望的方向,但我仍然没有弄清楚。我可以使用 Selenium 的 get_eval 方法将 JavaScript 传递到页面。使用 this.browserbot 调用方法让我得到我需要的元素。

So:

所以:

  1. How do I build the file object that needs to be part of the mock drop event?
  2. How do I fire the drop event such that it gets picked up as if I had dropped a file in the div?
  1. 如何构建需要成为模拟放置事件一部分的文件对象?
  2. 我如何触发 drop 事件,使其被拾取,就像我在 div 中放置了一个文件一样?

回答by micred

I post an RSpec test that simulate files drag and drop using Selenium webdriver. It use jQuery to make and trigger a fake 'drop' event.

我发布了一个 RSpec 测试,它使用 Selenium webdriver 模拟文件拖放。它使用 jQuery 来制作和触发一个假的 'drop' 事件。

This code simulate drag and drop of a single file. For sake of simplicity I've stripped code that allow multiple files dropping. Tell me if you need it.

此代码模拟单个文件的拖放。为简单起见,我去掉了允许丢弃多个文件的代码。告诉我你是否需要它。

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.:remember to replace #fileDropArea with ID of your drop area.

PS:记得将#fileDropArea 替换为您放置区域的 ID。

P.P.S:don't use evaluate_script in place of execute_script, otherwise selenium get stuck evaluating complex jQuery objects!

PPS:不要使用evaluate_script 代替execute_script,否则selenium 在评估复杂的jQuery 对象时会卡住!

UPDATE:I've write a method you can reuse and do the stuff written above.

更新:我写了一个方法,你可以重用并做上面写的东西。

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

Usage:

用法:

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   

回答by Henry Wilson

As @Shmoopy asked for it, here's a C# translation of the code provided by @micred

正如@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);");
}

回答by Michael Blake

Note: you should also add

注意:您还应该添加

    e.originalEvent.dataTransfer.types = [ 'Files' ];

回答by Santiago Hernandez

You can use Blueduck Sda (http://sda.blueducktesting.com) Is an OSS that has implemented ALL selenium functions (It works with selenium RC) but it allows you to automate Windows actions. So you can test web, and interact with the OS. So you can make your test, and then, just tell the mouse to click on the element and drop it where you want!

您可以使用 Blueduck Sda (http://sda.blueducktesting.com) 是一个实现了所有 selenium 功能的 OSS(它与 selenium RC 一起使用),但它允许您自动执行 Windows 操作。因此,您可以测试 Web,并与操作系统进行交互。因此,您可以进行测试,然后,只需告诉鼠标单击该元素并将其放到您想要的位置即可!

Nice testing!

不错的测试!