I am writing my acceptance tests using Capybara and Poltergeist driver.I need to validate the content of the CSV file downloaded.
Finally I want to settle down with the option of downloading the file in a specific folder and then read the CSV file using core ruby libraries.
In order to achieve this,when poltergeist driver clicks on download link then I want it to handle the pop-up and download the file directly in the given folder.
In Selenium's chrome and firefox drivers, I have option of configuring profiles to handle pop ups and configure download directory.
Is there any such option using poltergeist? Any information will be helpful.
It is not possible with Poltergeist, you can just check the headers.
step 'I should get zipped file' do
page.response_headers['Content-Disposition'].should include("filename=\"file.zip\"")
end
But is is possible with Chrome driver and also with recent versions of Firefox and Selenium Webdriver. Unfortunately it runs via Selenium - i.e. not headless... See this article: http://collectiveidea.com/blog/archives/2012/01/27/testing-file-downloads-with-capybara-and-chromedriver/
My approach - slightly different as I'm working with Spinach and Rubyzip:
Add the following to your Gemfile
group :test do
gem 'chromedriver-helper' # for Chrome <= 28
gem 'chromedriver2-helper' # for Chrome >= 29
gem 'selenium-webdriver'
end
features/support/capybara.rb - I'm using Poltergeist for scenarios with @javascript
tag and Chrome for scenarios with @download
tag.
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
features/support/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
features/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 - Note that you can't use page.response_headers
as it is not supported by the Selenium/ChromeDriver. But you can check the filename of the downloaded file using the 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