如何在Capybara和RSpec中测试CSV文件下载?

如何在Capybara和RSpec中测试CSV文件下载?

问题描述:

以下内容在控制器中:

respond_to do |format|
  format.csv  { send_data as_csv, type:'text/csv' }
end

规格:

click_link 'Download CSV'
page.driver.browser.switch_to.alert.accept

expect( page ).to have_content csv_data

但这不是工作:

Failure/Error: page.driver.browser.switch_to.alert.accept
Selenium::WebDriver::Error::NoAlertPresentError: No alert is present

我看到保存文件对话框显示,但显然它不是警告对话框。

I see the Save File dialog box display, but apparently it is not an "alert" dialog.

如何单击确定并获得水豚以查看数据?

How to click OK and get Capybara to see the data?

改编自 CollectiveIdea 和其他来源。

可在OSX上使用。 Firefox 34.0.5

Works on OSX. Firefox 34.0.5

规范:

  describe 'Download CSV' do
    let( :submission_email ){ 'foo@example.com' }
    let( :email_csv ){ "id,email,created_at\n1,#{ submission_email }," }

    specify do
      visit '/emails'
      expect( page ).to have_content 'Email Submissions'

      click_on 'Download CSV'

      expect( DownloadHelpers::download_content ).to include email_csv
    end
  end

规范助手:

require 'shared/download_helper'

Capybara.register_driver :selenium do |app|
  profile = Selenium::WebDriver::Firefox::Profile.new
  profile['browser.download.dir'] = DownloadHelpers::PATH.to_s
  profile['browser.download.folderList'] = 2

  # Suppress "open with" dialog
  profile['browser.helperApps.neverAsk.saveToDisk'] = 'text/csv'
  Capybara::Selenium::Driver.new(app, :browser => :firefox, :profile => profile)
end

config.before( :each ) do
    DownloadHelpers::clear_downloads
end

shared / download_helper.rb:

shared/download_helper.rb:

module DownloadHelpers
  TIMEOUT = 1
  PATH    = Rails.root.join("tmp/downloads")

  extend self

  def downloads
    Dir[PATH.join("*")]
  end

  def download
    downloads.first
  end

  def download_content
    wait_for_download
    File.read(download)
  end

  def wait_for_download
    Timeout.timeout(TIMEOUT) do
      sleep 0.1 until downloaded?
    end
  end

  def downloaded?
    !downloading? && downloads.any?
  end

  def downloading?
    downloads.grep(/\.part$/).any?
  end

  def clear_downloads
    FileUtils.rm_f(downloads)
  end
end