2

How To Download a File

The Problem

Just like with uploading files, we hit the same issue with downloading them. A dialog box just out of Selenium's reach.

A Solution

By specifying some configuration parameters when loading Selenium we can easily side-step the dialog box. This is done by instructing the browser to download files to a specific location without prompting.

After the file is downloaded we can perform some simple checks to make sure the file is what we expect.

Let's dig in with an example.

An Example

We start off by pulling in our requisite libraries (selenium-webdriver to drive the browser, rspec/expectations and RSpec::Matchers for assertions, uuid to help create a uniquely named temp directory, and fileutils to create and destroy temp directories).

# filename: download.rb

require 'selenium-webdriver'
require 'rspec/expectations'
include RSpec::Matchers
require 'uuid'
require 'fileutils'

def setup
  @download_dir = File.join(Dir.pwd, UUID.new.generate)
  FileUtils.mkdir_p @download_dir

  profile = Selenium::WebDriver::Firefox::Profile.new
  profile['browser.download.dir'] = @download_dir
  profile['browser.download.folderList'] = 2
  profile['browser.helperApps.neverAsk.saveToDisk'] = 'images/jpeg, application/pdf'
  profile['pdfjs.disabled'] = true
  @driver = Selenium::WebDriver.for :firefox, profile: profile
end

The setup method is where the magic is happening in this example. In it we're creating a uniquely named temp directory and storing the absolute path in an instance variable that we'll use throughout this file.

We're also configuring a browser profile object (for Firefox in this case) and plying it with configuration parameters. Here's a breakdown of each of them:

  • browser.download.folderList takes a number. It tells Firefox which download directory to use. 2 tells it to use a custom download path, wheras 1 would use the browser's default path, and 0 would place them on the Desktop.
  • browser.download.dir accepts a string. This is how we set the custom download path. It needs to be an absolute path.
  • browser.helperApps.neverAsk.saveToDisk tells Firefox when not to prompt for a file download. It accepts a string of the file's MIME type. If you want to specify more than one, you do it with a comma-separated string.
  • pdfjs.disabled is for when downloading PDFs. This overrides the sensible default in Firefox that previews PDFs in the browser. It accepts a boolean.
def teardown
  @driver.quit
  FileUtils.rm_rf @download_dir
end

def run
  setup
  yield
  teardown
end

In teardown we make sure to clean up the temp directory after closing the browser. Other than that, it's business as usual.

Now onto the test itself.

run do
  @driver.get 'http://the-internet.herokuapp.com/download'
  download_link = @driver.find_element(css: '.example a')
  download_link.click

  files = Dir.glob("#{@download_dir}/**")
  expect(files.empty?).to eql false

  sorted_files = files.sort_by { |file| File.mtime(file) }
  expect(File.size(sorted_files.last)).to be > 0
end

After loading the page we find the first download link and click it. Alternatively, we could have clicked the second link.

download_link = @driver.find_elements(css: '.example a')[1]

The click triggers an automatic download to the temp directory specified and created in setup. After that, we perform some rudimentary checks to make sure the directory isn't empty and that the most recently downloaded file has a file size greater than 0.

Expected Behavior

If you save this file and run it (e.g., ruby download.rb from the command-line) here is what would occur:

  • Create temp directory with a unique ID
  • Load the browser
  • Visit the page
  • Find and click one of the download links on the page
  • Automatically download the file to the specified location on disk without prompting
  • Check that a file was downloaded and that it's not empty
  • Close the browser
  • Delete the temp directory

Outro

A similar approach can be applied to other browsers with varying configurations, but really, downloading files this way is not sustainable or advised.

Stay tuned to a future tip where I'll cover a more reliable, faster, and scalable browser agnostic approach to downloading files.

Until then, Happy Testing!

Found this helpful?

Submit your e-mail in the form below to recieve tips like this!

One email every Tuesday. No Spam. Ever. Unsubscribe anytime.


Back to the archives