Collective Idea

Collective Idea Logo

Steve Richert

Testing File Downloads with Capybara and ChromeDriver

By Steve Richert on January 27, 2012 in capybara, chromedriver, and cucumber

At Collective Idea, we Cucumber, Capybara and ChromeDriver… and alliteration. But we recently encountered an issue with a very Ajaxy Rails app where we need to test a file download and assert its content.

Our scenario looks like:

Scenario: Exporting the fruits list
  Given the following fruits exist:
    | Name   | Color  |
    | Apple  | Red    |
    | Orange | Orange |
    | Lemon  | Yellow |
  And I am on the fruits page
  When I follow "Export"
  Then the downloaded file content should be:

Easy enough! Early in the app’s life, we wrote this Cucumber step:

Then "the downloaded file content should be:" do |content|
  page.response_headers["Content-Disposition"].should == "attachment"
  page.source.should == content

This worked like gangbusters. But with such an Ajaxy app, we soon moved to ChromeDriver as our default Capybara driver and our nice green scenario turned an annoying shade of red.

When the scenario ran, Chrome triggered the download as expected but threw the file into my “Downloads” directory. Capybara had no reference to its content and to make matters worse, Cucumber didn’t wait for the download to finish before moving on.

After much frustration…

We discovered that it’s possible to provide a Chrome profile (just a collection of settings) when registering the :chrome Capybara driver. We’re registering the driver in features/support/chromedriver.rb so we added the profile there:

require "selenium/webdriver"

Capybara.register_driver :chrome do |app|
  profile =
  profile["download.default_directory"] = DownloadHelpers::PATH.to_s, :browser => :chrome, :profile => profile)

Capybara.default_driver = Capybara.javascript_driver = :chrome

We added a download.default_directory setting to the profile. This tells the browser where to send downloaded files. Eureka!

That answers the question of downloading the file to the proper place, but we still need to make sure we wait for the download to finish. We take care of that in features/support/downloads.rb:

module DownloadHelpers
  TIMEOUT = 10
  PATH    = Rails.root.join("tmp/downloads")

  extend self

  def downloads

  def download

  def download_content

  def wait_for_download
    Timeout.timeout(TIMEOUT) do
      sleep 0.1 until downloaded?

  def downloaded?
    !downloading? && downloads.any?

  def downloading?

  def clear_downloads


Before do

After do

Now we’re equipped with everything we need to effectively manage and inspect file downloads. Our Cucumber step simply changes to:

Then "the downloaded file content should be:" do |content|
  download_content.should == content

And there you have it. It’s a little bit of added support code but if you’re dealing with downloads, it’s well worth your while.

By Steve Richert on January 27, 2012 in capybara, chromedriver, and cucumber


  1. rad

    rad February 11, 2012 http://www.onedlp.cpm

    first timer .. loved ur site .. loved ur approaches ..

  2. CongDang

    CongDang May 31, 2012

    Any sample code for java guys?

  3. artem

    artem March 21, 2013

    Very helpful, thanks!

    typo: there is an extra ‘s’ in ‘World(DownloadsHelpers)’

  4. Steve Richert

    Steve Richert March 21, 2013

    @artem: Thanks, and fixed!

  5. artem

    artem March 26, 2013

    Here is firefox profile:

    Capybara.register_driver :firefox do |app|
      profile =
      profile[‘’] = DownloadHelpers::PATH.to_s
      # means save to the ‘’ as opposed to ~/Downloads
      profile[‘’] = 2
      # prevents “open with” dialog
      profile[‘browser.helperApps.neverAsk.saveToDisk’] = ‘application/vnd.openxmlformats-officedocument.spreadsheetml.sheet’, :browser => :firefox, :profile => profile)

  6. Chris LaBrunda

    Chris LaBrunda November 25, 2013

    We’ve been using this successfully for a while, but noticed some intermittent failures on some of our download tests.  The problem manifested as the downloaded file being empty when our test examined it.

    To fix it, I increased the timeout, but more importantly I switched the order of the test to see if the file finished downloading.  Your `downloaded?` function checks to see if chrome’s partial download file marker does not exist, then checks to see if any files exist after that.  It’s possible that the file could start downloading between the two tests, however, which could lead to the function falsely returning true.  My `downloaded?` function instead looks like:

      def downloaded?
        downloads.any? && !downloading?

    This has been passing consistently for the past two weeks.  Hope this helps someone.

  7. mangala

    mangala February 11, 2015

    Any Configuration for Internet Explorer for storing downloaded files to specific path?

  8. Gabe Pumple

    Gabe Pumple April 17, 2015

    Thanks so much, found this super helpful. One question though: do you have any idea how to change the chrome profile so that the files won’t be shown down at the bottom of the browser window? I am having a problem where chrome can’t click an element because once a file is downloaded the window is slightly smaller.

  9. Steve

    Steve April 17, 2015

    Gabe: Sorry, I’m stumped on that one!

  10. Chris

    Chris April 27, 2015

    Any suggestion on how to make this work for Safari?

Post a Comment

Contact Us

Find us on Google Maps
Collective Idea
44 East 8th Street, Suite 410
Holland, Michigan 49423 USA 42.790334-86.105251


Follow us on the Interwebs

We are currently available for medium and long term projects. Please get in touch if we can be of service.