DEV Community

Alessandro Rodi
Alessandro Rodi

Posted on

Test downloaded files with RSpec and System Tests

Scenario

You have a download button, that downloads a dynamically generated file, and you want to test that the file is downloaded correctly. A request test is not sufficient, because the file changes, depending on the actions performed by the user in previous steps, so you want to test that in a system test.

Solution

The solution is based on the fact that you are using rspec, selenium-webdriver and Chrome to run you tests.

First of all, you need a custom driver, that is able to manage downloads. You can add the following to the rails_helper:

Capybara.register_driver :selenium_chrome_headless do |app| browser_options = ::Selenium::WebDriver::Chrome::Options.new.tap do |opts| opts.args << '--headless' opts.args << '--disable-site-isolation-trials' end browser_options.add_preference(:download, prompt_for_download: false, default_directory: DownloadHelpers::PATH.to_s) browser_options.add_preference(:browser, set_download_behavior: { behavior: 'allow' }) Capybara::Selenium::Driver.new(app, browser: :chrome, options: browser_options) end 
Enter fullscreen mode Exit fullscreen mode

and implement a DownloadHelper module:

module DownloadHelpers TIMEOUT = 10 PATH = Rails.root.join('tmp/downloads') def downloads Dir[PATH.join('*')] end def download downloads.first end def download_content wait_for_download File.read(download) end def wait_for_download Timeout.timeout(TIMEOUT) do sleep 0.1 until downloaded? end end def downloaded? !downloading? && downloads.any? end def downloading? downloads.grep(/\.crdownload$/).any? end def clear_downloads FileUtils.rm_f(downloads) end end 
Enter fullscreen mode Exit fullscreen mode

Now, you have a driver, that is able to manage downloads. Use it and clean the downloads before and after each test. So, magain, in the rails_helper.rb:

config.before(:each, type: :system, js: true) do clear_downloads driven_by :selenium_chrome_headless end config.after(:each, type: :system, js: true) do clear_downloads end 
Enter fullscreen mode Exit fullscreen mode

and here is a small example of usage in a system test:

visit the_page_with_download_button_path find("Download as PDF").click wait_for_download expect(downloads.length).to eq(1) expect(download).to match(/.*\.pdf/) 
Enter fullscreen mode Exit fullscreen mode

If you want, the driver above is available as selenium_chrome_with_downloads and selenium_chrome_headless_with_downloads in the so_many_devices gem, kindly offered by Renuo.

Top comments (1)

Collapse
 
michaelodumosu57 profile image
Michael Odumosu • Edited

Absolute lifesaver I have modified the downloadshelper to work with non Rails applications specifically Angular, why I choose capybara, so simple to mimick and complicated e2e such as file download. Subscribe to our youtube channel we really want to mention when we do a video on it youtube.com/channel/UCmqEX_zasOf3A...