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 |
Posted by Henning Koch to makandra dev (2022-05-03 14:54)