20

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

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

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

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

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

使用 poltergeist 有没有这样的选择?任何信息都会有所帮助。

4

4 回答 4

24

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

功能/支持/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

功能/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
于 2013-04-25T14:28:57.477 回答
15

我不得不在我的 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

祝你好运。希望这可以帮助。

于 2013-06-14T14:48:02.857 回答
4

Poltergeist 目前无法做到这一点。

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

于 2013-04-02T12:31:35.757 回答
2

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

于 2014-02-18T23:05:00.573 回答