如何在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

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

如何单击确定并让Capybara查看数据?

改编自CollectiveIdea和其他来源。

适用于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 

共享/ 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 

我试图实现类似的东西,花了很多时间。 最后我有一些解决方案,也许它也适合你。

的Gemfile:

 #source 'https://rubygems.org' gem 'rails', '4.2.2' gem 'bcrypt', '3.1.7' gem 'bootstrap-sass', '3.2.0.0' gem 'faker', '1.4.2' gem 'carrierwave', '0.10.0' gem 'mini_magick', '3.8.0' gem 'fog', '1.36.0' gem 'will_paginate', '3.0.7' gem 'bootstrap-will_paginate', '0.0.10' gem 'sass-rails', '5.0.2' gem 'uglifier', '2.5.3' gem 'coffee-rails', '4.1.0' gem 'jquery-rails', '4.0.3' gem 'turbolinks', '2.3.0' gem 'jbuilder', '2.2.3' gem 'sdoc', '0.4.0', group: :doc gem 'rename' gem 'sprockets', '3.6.3' gem 'responders', '~> 2.0' gem 'inherited_resources' group :development, :test do gem 'sqlite3', '1.3.9' gem 'byebug', '3.4.0' gem 'web-console', '2.0.0.beta3' gem 'spring', '1.1.3' end group :test do gem 'minitest-reporters', '1.0.5' gem 'mini_backtrace', '0.1.3' gem 'guard-minitest', '2.3.1' gem 'capybara', '2.8.1' gem 'rspec', '3.5.0' gem 'rspec-rails', '~> 3.4' gem 'cucumber-rails', :require => false gem 'shoulda-matchers', '~> 3.0', require: false gem 'database_cleaner' gem 'factory_girl_rails', '~> 4.5.0' end 

投机/ rails_helper.rb

 ENV['RAILS_ENV'] ||= 'test' require File.expand_path('../../config/environment', __FILE__) abort("The Rails environment is running in production mode!") if Rails.env.production? require 'spec_helper' require 'rspec/rails' require 'shoulda/matchers' Shoulda::Matchers.configure do |config| config.integrate do |with| with.test_framework :rspec with.library :rails end end config.use_transactional_fixtures = false ActiveRecord::Migration.maintain_test_schema! RSpec.configure do |config| config.fixture_path = "#{::Rails.root}/spec/fixtures" config.use_transactional_fixtures = true config.infer_spec_type_from_file_location! config.filter_rails_from_backtrace! end 

投机/ spec_helper.rb

 ENV["RAILS_ENV"] ||= 'test' require File.expand_path("../../config/environment", __FILE__) require 'rspec/rails' require 'capybara/rspec' require 'capybara/rails' require '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 profile['browser.helperApps.neverAsk.saveToDisk'] = 'text/csv' Capybara::Selenium::Driver.new(app, :browser => :firefox, :profile => profile) end RSpec.configure do |config| config.expect_with :rspec do |expectations| expectations.include_chain_clauses_in_custom_matcher_descriptions = true end config.mock_with :rspec do |mocks| mocks.verify_partial_doubles = true end config.shared_context_metadata_behavior = :apply_to_host_groups config.include Capybara::DSL =begin config.filter_run_when_matching :focus config.example_status_persistence_file_path = "spec/examples.txt" config.disable_monkey_patching! if config.files_to_run.one? config.default_formatter = 'doc' end config.profile_examples = 10 config.order = :random Kernel.srand config.seed =end end 

测试/ test_helper.rb中

 ENV['RAILS_ENV'] ||= 'test' require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' require 'capybara/rails' class ActiveSupport::TestCase # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. fixtures :all include ApplicationHelper def is_logged_in? !session[:user_id].nil? end # Logs in a test user. def log_in_as(user, options = {}) password = options[:password] || 'password' remember_me = options[:remember_me] || '1' if integration_test? post login_path, session: { email:user.email, password: password, remember_me: remember_me } else session[:user_id] = user.id end end private # Returns true inside an integration test. def integration_test? defined?(post_via_redirect) end end class ActionDispatch::IntegrationTest # Make the Capybara DSL available in all integration tests include Capybara::DSL # Reset sessions and driver between tests # Use super wherever this method is redefined in your individual test classes def teardown Capybara.reset_sessions! Capybara.use_default_driver end end 

投机/ 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 

规格/ mpodels / spec.rb

  describe 'Download file' do specify do visit '/createfile' click_on 'create file' page.response_headers['Content-Type'].should == "text/csv" header = page.response_headers['Content-Disposition'] header.should match /^attachment/ header.should match /filename=\"temp.csv\"$/ end end 

我找到了另一种方法,如果你使用的是rack_test驱动程序(没有javascript /没有浏览器):

 DOWNLOAD_CACHE_PATH = Rails.root.join("tmp/downloaded_file").to_s setup do File.delete(DOWNLOAD_CACHE_PATH) end test "download file" do visit download_file_path # simulate file download File.write(DOWNLOAD_CACHE_PATH, page.body) csv = CSV.open(DOWNLOAD_CACHE_PATH) # assert something on the csv data end 

根据浏览器的不同,您需要该浏览器的配置文件,我建议禁用要求在该配置文件中保存的属性。