2015-03-27 7 views
5

Quello che segue è nel controller:Come testare il download di file CSV in Capybara e RSpec?

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

In spec:

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

expect(page).to have_content csv_data 

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

vedo il Salva file di visualizzazione della finestra di dialogo, ma a quanto pare non è una finestra di "avviso".

Come fare clic su OK e ottenere Capybara per vedere i dati?

risposta

9

Adattato da CollectiveIdea e un'altra fonte.

Funziona su OSX. Firefox 34.0.5

Spec:

describe 'Download CSV' do 
    let(:submission_email){ '[email protected]' } 
    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 

Spec aiutante:

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 

condiviso/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 
+0

perché stai usando: lasciare (: submission_email) { '[email protected]'} let (: email_csv) { "id, e-mail, created_at \ n1, # {} submission_email,"} – ChaosPredictor

+0

Sto ottenendo: impossibile caricare tale file - shared/download_helper.rb (LoadError) quando spec_helper run richiede la riga 'shared/download_helper'. il download_helper.rb è nel posto giusto. – ChaosPredictor

1

A seconda del browser è necessario un profilo per quel browser e suggerirei di disabilitare la proprietà che richiede il salvataggio in quel profilo.

1

Ho cercato di implementare qualcosa di simile e spendere un sacco di ore. Finalmente ho qualche soluzione, forse anche per te.

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 

spec/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/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/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 

spec/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 

spec/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 
1

ho trovato un altro modo per fare questo, se si sta utilizzando il driver rack_test (javascript/nessun browser):

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 
Problemi correlati