【问题标题】:Downloading file to specific folder using Capybara and Poltergeist driver使用 Capybara 和 Poltergeist 驱动程序将文件下载到特定文件夹
【发布时间】:2013-04-01 07:29:48
【问题描述】:

我正在使用 Capybara 和 Poltergeist 驱动程序编写验收测试。我需要验证下载的 CSV 文件的内容。

  1. 我尝试了各种方法来呈现页面本身的内容,而不是下载它。
  2. 还尝试更改 mime 类型,但它不起作用。

最后,我想选择将文件下载到特定文件夹中,然后使用核心 ruby​​ 库读取 CSV 文件。

为了实现这一点,当 poltergeist 驱动程序单击下载链接时,我希望它处理弹出窗口并直接在给定文件夹中下载文件。

在 Selenium 的 chrome 和 firefox 驱动程序中,我可以选择配置配置文件来处理弹出窗口和配置下载目录。

是否有任何使用 poltergeist 的选项?任何信息都会有所帮助。

【问题讨论】:

    标签: capybara poltergeist


    【解决方案1】:

    Poltergeist 无法做到这一点,您只需检查标题即可。

     step 'I should get zipped file' do
        page.response_headers['Content-Disposition'].should include("filename=\"file.zip\"")
     end
    

    但是可以使用 Chrome 驱动程序以及最新版本的 Firefox 和 Selenium Webdriver。不幸的是,它通过 Selenium 运行 - 即不是无头的......请参阅这篇文章:http://collectiveidea.com/blog/archives/2012/01/27/testing-file-downloads-with-capybara-and-chromedriver/

    我的方法 - 在使用 Spinach 和 Rubyzip 时略有不同:

    将以下内容添加到您的 Gemfile

    group :test do
      gem 'chromedriver-helper'  # for Chrome <= 28
      gem 'chromedriver2-helper' # for Chrome >= 29
      gem 'selenium-webdriver'
    end
    

    features/support/capybara.rb - 我将 Poltergeist 用于带有 @javascript 标签的场景,而 Chrome 用于带有 @download 标签的场景。

    require 'spinach/capybara'
    require 'capybara/poltergeist'
    require 'selenium/webdriver'
    
    # ChromeDriver 1.x, for Chrome <= 28 
    Capybara.register_driver :chrome do |app|
      profile = Selenium::WebDriver::Chrome::Profile.new
      profile['download.default_directory'] = DownloadHelper::PATH.to_s
      args = ["--window-size=1024,768"]
      Capybara::Selenium::Driver.new(app, browser: :chrome, profile: profile, args: args)
    end
    
    # ChromeDriver 2.x, for Chrome >= 29 
    Capybara.register_driver :chrome do |app|
      prefs = {
        download: {
          prompt_for_download: false,
          default_directory: DownloadHelper::PATH.to_s
        }
      }
      args = ['--window-size=1024,768']
      Capybara::Selenium::Driver.new(app, browser: :chrome, prefs: prefs, args: args)
    end
    
    # Tested with Firefox 27 and Selenium Webdriver 2.39
    Capybara.register_driver :firefox do |app|
      profile = Selenium::WebDriver::Firefox::Profile.new
      profile['browser.download.dir'] = DownloadHelper::PATH.to_s
      profile['browser.download.folderList'] = 2 # 2 - save to user defined location
      profile['browser.helperApps.neverAsk.saveToDisk'] = 'application/zip'
      Capybara::Selenium::Driver.new(app, browser: :firefox, profile: profile)
    end
    
    Capybara.javascript_driver = :poltergeist # :webkit :selenium :poltergeist :chrome
    
    Spinach.hooks.on_tag("javascript") do
      Capybara.current_driver = Capybara.javascript_driver
      Capybara.default_wait_time = 5
    end
    
    Spinach.hooks.on_tag("download") do
      Capybara.current_driver = :chrome # or :firefox
      Capybara.default_wait_time = 50
    end
    

    features/support/downloads.rb

    module DownloadHelper
      TIMEOUT = 10
      PATH    = Rails.root.join("tmp/downloads")
    
      extend self
    
      def downloads
        Dir[PATH.join("*")]
      end
    
      def download_path
        wait_for_download
        downloads.first
      end
    
      def download_content
        wait_for_download
        File.read(download_path)
      end
    
      def wait_for_download
        Timeout.timeout(TIMEOUT) do
          sleep 0.1 until downloaded?
        end
      end
    
      def downloaded?
        downloads.any? && !downloading?
      end
    
      def downloading?
        downloads.grep(/\.crdownload$/).any?
      end
    
      def clear_downloads
        FileUtils.rm_f(downloads)
      end
    
    end
    
    Spinach.hooks.before_scenario do |scenario|
      DownloadHelper.clear_downloads
    end
    
    Spinach.hooks.after_scenario do
      DownloadHelper.clear_downloads
    end
    

    features/file_download.feature

    Feature: File download
       As a user
       I want to be able to download my files
    
    Background:
      Given I am logged in as a user
      And I have uploaded files in the system
    
    @download
    Scenario: Successfull download
      When I click on the download button
      Then I should get zipped files
    

    features/steps/file_download.rb - 请注意,您不能使用 page.response_headers,因为 Selenium/ChromeDriver 不支持它。但是你可以使用File.basename()查看下载文件的文件名。

    class Spinach::Features::FileDownload < Spinach::FeatureSteps
      include SharedAuthentication
    
      step 'I click on the download button' do
        click_link "Download"
      end
    
      step 'I should get zipped files' do
        File.basename(DownloadHelper.download_path).should == 'file.zip'
        Zip::ZipFile.open(DownloadHelper.download_path) do |zipfile|
          zipfile.find_entry('myfile.txt').should_not be_nil
          zipfile.find_entry('myphoto.jpg').should_not be_nil
        end
      end
    
    end
    

    【讨论】:

    • 当我尝试使用 poltergeist 并仅检查标题 (page.response_headers) 时,它显然返回了最后一个 HTML 页面的标题,而不是我触发下载的 PDF 文件 - 页面。 response_headers['Content-Type'] 是“text/html”...我想知道是不是有什么变化或者我做错了什么?仅使用常规 :selenium (WebDriver) 驱动程序就可以正常工作,当我循环直到下载的文件完成下载时,就像在您的示例中一样...
    • 这可能是 ChromeDriver 的问题,因为我最初的示例是为 ChromeDriver 1.x 和 Chromium v​​29 编写的。
    • 但是对于 Chromium 29+,您需要使用 ChromeDriver 2.x。您可以在这里下载它:chromedriver.storage.googleapis.com/index.html 并将其移动到可执行路径。或者你可以使用chromedriver2-helper gem。但不幸的是,ChromeDriver 2.x 需要稍微不同的文档。在最近的实验中,我让 DownloadHelper 也可以与 Firefox 一起使用。
    • 我已经编辑了上面的示例并添加了 ChromeDriver 2.x 和 Firefox(!) 的示例配置
    【解决方案2】:

    我不得不在我的 rails 应用程序中做类似的事情。我的解决方案是使用 Javascript 向 URL 发出 XMLHttpRequest,下载文件,将文件内容返回给 Capybara,然后使用 ruby​​ 将文件保存在磁盘上的某个位置。然后在另一个步骤中,我检查下载的 CSV 文件的内容。

    这是下载文件的步骤定义:

    Then /^I download the csv file$/ do
      page.execute_script("window.downloadCSVXHR = function(){ var url = window.location.protocol + '//' + window.location.host + '/file.csv'; return getFile(url); }")
      page.execute_script("window.getFile = function(url) { var xhr = new XMLHttpRequest();  xhr.open('GET', url, false);  xhr.send(null); return xhr.responseText; }")
    
      data = page.evaluate_script("downloadCSVXHR()")
      File.open(File.join(Rails.root, "tmp", "csv.data"), "w") { |f| f.write(data) }
    end
    

    将 Javascript 代码中的 URL 更改为 CSV 的位置。

    最后,这是我验证 CSV 文件内容的步骤定义:

    And /^the contents of the downloaded csv should be:$/ do |contents|
      file = File.open(File.join(Rails.root, "tmp", "csv.data"), "r")
      file_contents = file.read
      file_contents.chop!
      file_contents.should == contents
    end
    

    祝你好运。希望这会有所帮助。

    【讨论】:

    • 谢谢,这是一个非常好的解决方案!
    • 我不得不更新到 PhantomJS 2.1 并且这个解决方案不再起作用了。任何想法如何让它工作?
    【解决方案3】:

    Poltergeist 目前无法做到这一点。

    我认为你最好为这个不使用 Capybara 的 CSV 编写一个测试。 (例如,通过使用内置的 Rails 集成测试内容并将响应解析为 CSV。)

    【讨论】:

      【解决方案4】:

      有一张支持在 PhantomJS/Poltergeist 中下载文件的票证,并且有一两个分支声称他们以某种方式使其工作。见https://github.com/ariya/phantomjs/issues/10052

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多