【问题标题】:Using Selenium to imitate dragging a file onto an upload element使用 Selenium 模拟将文件拖到上传元素上
【发布时间】:2011-07-08 11:27:12
【问题描述】:

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

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

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

所以:

  1. 如何构建文件对象 需要成为模拟下降的一部分 事件?
  2. 如何触发 drop 事件 这样它就会被捡起来,就好像我 在 div 中删除了一个文件?

【问题讨论】:

    标签: javascript ruby selenium


    【解决方案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。通过将 $('&lt;input id=\"" + inputId + "\"/&gt;').attr({type:'file'}) 更改为 $('&lt;input id=\"" + inputId + "\" type=\"file\" /&gt;') 来修复。
    【解决方案3】:

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

    很好的测试!

    【讨论】:

    • 这看起来可能是一个选项,虽然我在 OSX 中工作,而不是 Windows。我也对在 JavaScript 上下文中与浏览器机器人交互和触发事件感到好奇。
    • 在撰写本文时 blueducktesting.com 域名正在出售中。
    【解决方案4】:

    注意:您还应该添加

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

    【讨论】:

      猜你喜欢
      • 2020-08-06
      • 1970-01-01
      • 1970-01-01
      • 2021-01-09
      • 2020-09-16
      • 1970-01-01
      • 2020-07-21
      • 2016-08-06
      相关资源
      最近更新 更多