2016-06-21 16 views
0

更新:燒了太多小時後,決定選擇簡單的方法,並使用機架測試。這可以直接使用,並至少驗證內容類型是pdf。執行過期軌道功能規格測試下載使用水豚/硒/火狐

scenario 'document can be downloaded' do 
    visit my_documents_path 

    click_on 'Download' 
    expect(page.response_headers['Content-Type']).to eq "application/pdf" 
end 

我想寫一個功能規格來測試我下載的PDF中的內容,我也跟着在這裏找到了方向:https://stackoverflow.com/a/29544674/2464546

我運行的Ruby 2.3的Rails 4.2。 5.2,RSpec 3.4,水豚2.7。

在從上面的SO鏈接的代碼中,有一條線,據稱抑制火狐保存彈出,這一點,調整到pdfcsv

# Suppress "open with" dialog 
profile['browser.helperApps.neverAsk.saveToDisk'] = 'application/pdf' 

這似乎並沒有因爲對話框工作盒子仍然彈出,然後我的測試出錯。

我的功能規格:

scenario 'document can be downloaded', js: true do 
    visit my_documents_path 

    click_on 'Download' 

    expect(DownloadHelpers::download_content).to have_content('Thingy') 
end 

我每次運行這個規範,它錯誤說出來,每次execution expired有不同的錯誤。例如,最近的一次了下列文件:

1) My documents home page document can be downloaded 
Failure/Error: Dir[PATH.join("*")] 

Timeout::Error: 
    execution expired 
# ./spec/features/shared/download_helper.rb:8:in `downloads' 
# ./spec/features/shared/download_helper.rb:31:in `downloading?' 
# ./spec/features/shared/download_helper.rb:27:in `downloaded?' 
# ./spec/features/shared/download_helper.rb:22:in `block in wait_for_download' 
# ./spec/features/shared/download_helper.rb:21:in `wait_for_download' 
# ./spec/features/shared/download_helper.rb:16:in `download_content' 
# ./spec/features/my_documents/index_spec.rb:42:in `block (2 levels) in <top (required)>' 

DownloadHelpers模塊,我已經從0.1改變了sleep 1〜3,偶爾我會得到下面的錯誤,與睡眠數改變w^/無論我將它設置爲:

Failure/Error: sleep 3 until downloaded? 

Timeout::Error: 
    execution expired 
# ./spec/features/shared/download_helper.rb:22:in `sleep' 
# ./spec/features/shared/download_helper.rb:22:in `block in wait_for_download' 
# ./spec/features/shared/download_helper.rb:21:in `wait_for_download' 
# ./spec/features/shared/download_helper.rb:16:in `download_content' 
# ./spec/features/my_documents/index_spec.rb:42:in `block (2 levels) in <top (required)>' 

我也與上述失敗的結果沒有變化改變了TIMEOUT計數。最終,對話框仍然彈出並且不會消失/看起來不像它下載文件。

我的下載按鈕後面的控制器:

def download 
    pdf = @document.pdf_file_name 

    send_file pdf 
end 

創建的文件並不大,因爲所有它是一個名字和幾行,所以我不懷疑它會需要比更幾秒鐘下載並讀取文件。

爲什麼執行過期?如何獲得水豚/特徵規格下載文件,以便我的期望通過?

該視圖document.haml使用角度壽我不認爲這很重要。

 %li.col-xs-6 
     %li.col-xs-6= link_to 'Download', download_document_path(id: document.id), "ng-click" => "logAnalytics('#{document.document_template_id}', 'download')" 

另外,我的功能規格有require 'rails_helper'在頂部,而我rails_helper具有從SO後的代碼(完全,W /相關位):

require 'features/shared/download_helper' 

RSpec.configure do |config| 

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'] = 'application/pdf' 
    Capybara::Selenium::Driver.new(app, browser: :firefox, profile: profile) 
end 

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

回答

0

我認爲,任何的下面的工作:

page.driver.browser.switch_to.alert.accept 
# or 
page.driver.browser.switch_to.alert.dismiss 
# or 
page.driver.browser.switch_to.alert.text 
+0

不幸的是,他們都給我一個錯誤,說它不是一個提醒。 'Selenium :: WebDriver :: Error :: NoSuchAlertError: No alert is present' –

+0

好吧,那麼你可以發佈你的視圖代碼? –

+0

我將更新帖子w /視圖代碼 –

0

檢查MIME類型的PDF下載文件恢復,賠率是它實際上不是「應用程序/ PDF」,是最有可能被返回「應用程序/八位字節流」。你應該修復返回類型是正確的,但在短期內,你可以嘗試更改爲profile['browser.helperApps.neverAsk.saveToDisk'] = 'application/pdf,application/octet-stream'

+0

不幸的是我已經嘗試添加,並沒有骰子。使用機架測試進行測試並檢查Content-Header時,它會顯示爲application/pdf。那個惡夢的對話框似乎永遠不會消失。 :\ –

+0

重讀你的問題,我注意到「#抑制」用「對話框」打開 - 它是一個保存對話框或打開?如果打開,你可能需要設置profile ['browser.helperApps.neverAsk.openFile'] ='application/pdf' - 如果它實際上是「打開的」對話框,你可能想看看修改你的鏈接到強制下載而不是 –

+0

使用Firefox是一個「保存或打開」對話框,這似乎是默認行爲。我從來沒有在rspec之外使用FF,所以我能夠複製它。我以爲'browser.helperApps.neverAsk。saveToDisk'是FF建議忽略該對話框。我嘗試'browser.helperApps.neverAsk.openFile'也無濟於事。這裏是[圖片](http://i.imgur.com/qWeNA3A.png) –

0

我試圖實現類似的東西,花費大量的時間。最後,我有一些解決方案,也許它也適合你。

的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 
0

我得到了 '執行過期' 的錯誤了。我遵循了上述所有步驟,但錯誤依然存在。原來在文件系統中缺少下載目錄(DownloadHelpers::PATH)。 創建該消息使消息消失並通過測試。