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

时间:2011-03-04 00:12:53

标签: javascript ruby selenium

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

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

如果发现interesting article似乎指向了一个充满希望的方向,但我仍然没有把它全部搞清楚。我可以使用Selenium的get_eval方法将JavaScript传递给页面。使用this.browserbot调用方法可以获得我需要的元素。

所以:

  1. 如何构建文件对象 需要成为模拟掉落的一部分 事件?
  2. 如何触发放置事件 这样它就像我一样被捡起来 在div中放了一个文件?

4 个答案:

答案 0 :(得分:29)

我发布了一个使用Selenium webdriver模拟文件拖放的RSpec测试。 它使用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。

P.P.S:不要使用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   

答案 1 :(得分:3)

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

答案 2 :(得分:0)

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

不错的测试!

答案 3 :(得分:0)

注意:您还应该添加

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