Posted 24 days ago. Visible to the public.

Capybara: Most okayest helper to download and inspect files

Testing file download links in an end-to-end test can be painful, especially with Selenium.

The attached download_helpers.rb provides a download_link method for your Capybara tests. It returns a hash describing the download's response:

details = download_link('Download report') details[:disposition] # => 'attachment' or 'inline' details[:filename] # => 'report.txt' details[:text] # => file content as string details[:content_type] # => 'text/plain'


Compared to other approaches this helper has many useful features:

  • Works with both Selenium and Rack::Test drivers without limitations.
  • Understands the [download] Archive and [download=filename.ext] attributes.
  • Allows filename, disposition, content type and text content of a download link to be inspected in Ruby.
  • Uses a filename from the response URL if no filename is sent by the server.
  • Does not leave the current page when downloading.
  • Works with both static files and send_file Archive .
  • Fails the test if the server doesn't respond with a HTTP 2xx status.
  • Works in CI.


  • The helper cannot inspect downloads that are triggered or created by JavaScript.

For alternatives see Cucumber: Testing file downloads with Selenium.

Usage in RSpec feature specs

Copy the DownloadHelpers module to spec/support.

You can now include Archive the helper in all your feature specs:

RSpec.configure do |config| config.include(DownloadHelpers, type: :feature) end

Usage in Cucumber scenarios

Copy the DownloadHelpers module to features/support.

Then include the helper in your scenarios and define some step definitions:

World(DownloadHelpers) When('I download {string}') do |locator| @last_download = download_link(locator) end Then('the download should have the filename {string}') do |filename| expect(@last_download[:filename]).to eq(filename) end Then('the download should have the content type {string}') do |content_type| expect(@last_download[:content_type]).to eq(content_type) end Then /^the download should display as (attachment|inline)$/ do |filename| expect(@last_download[:disposition]).to eq(filename) end Then('the download should contain the following lines:') do |table| table.raw.each do |row| expect(@last_download[:text]).to include(*row), "Expected downloaded file to include \"#{row}\"" end end

You can now write steps like this:

Scenario: Download text file with Rack::Test When I go to the list of downloads And I download "download text" Then the download should display as attachment And the download should have the filename "test.txt" And the download should have the content type "text/plain" And the download should contain the following lines: | Line 1 | | Line 2 |

Your development team has a full backlog of feature requests, chores and refactoring coupled with deadlines? We are familiar with that. With our "DevOps as a Service" offering, we support developer teams with infrastructure and operations expertise.

Owner of this card:

Henning Koch
Last edit:
18 days ago
by Dominik Schöler
feature, cucumber, e2e, end-to-end, test
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Henning Koch to makandra dev
This website uses short-lived cookies to improve usability.
Accept or learn more