Capybara: Most okayest helper to download and inspect files

Updated . Posted . Visible to the public.

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'

Features

Compared to other approaches this helper has many useful features:

  • Works with both Selenium and Rack::Test drivers without limitations.
  • Understands the [download] Show archive.org snapshot 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 Show archive.org snapshot .
  • Fails the test if the server doesn't respond with a HTTP 2xx status.
  • Works in CI.

Limitations

  • The helper cannot inspect downloads that are triggered or created by JavaScript.
  • The helper cannot inspect downloads from a different hostname than that of the application.

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 Show archive.org snapshot 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 |
Henning Koch
Last edit
Henning Koch
Attachments
Keywords
feature, cucumber, e2e, end-to-end, test
License
Source code in this card is licensed under the MIT License.
Posted by Henning Koch to makandra dev (2022-05-03 14:54)