Take the 2-minute tour ×
Software Quality Assurance & Testing Stack Exchange is a question and answer site for software quality control experts, automation engineers, and software testers. It's 100% free, no registration required.

Basically I want to at least check that a download-able file exists / download link works and preferably get stuff like the file size too.

Here's an example:

link = self.browser.find_element_by_link_text('link text')
href = link.get_attribute('href')
download = self.browser.get(href)
print download

That fourth line prints "None", presumably because I haven't manually clicked the Save button, and even if I had, I doubt WebDriver would be able to "see" the file.

Any ideas? I'm using Firefox as my browser-under-test, and I understand that the file handling for downloads is somewhat browser and/or OS specific.

Thanks.

share|improve this question
    
Maybe it's better to see [this][1]. [1]: stackoverflow.com/questions/18439851/… –  Zeinab Abbasi Oct 30 '13 at 8:17

9 Answers 9

up vote 9 down vote accepted

As far as I know there is no easy way to make Selenium download files because browsers use native dialogs for it which cannot be controlled by JavaScript, so you need some "hack". Check this, hope it helps.

share|improve this answer
    
Thanks. I might try to do it with the Python requests module. –  Aaron Dec 2 '11 at 22:05
    
+1 but "Provide context for links Links to external resources are encouraged, but please add context around the link so your fellow users will have some idea what it is and why it’s there. Always quote the most relevant part of an important link, in case the target site is unreachable or goes permanently offline." as stated here: sqa.stackexchange.com/help/how-to-answer –  dzieciou Jun 28 at 17:53

Link to my blog where I discuss this in more detail.

First of all why do you want to download the file? Are you going to do anything with it?

The majority of poeple who want to download files just do it so that they can show an automation framework downloading files because it makes somebody non-technical ooo and ahh.

You can check the header response to check that you get a 200 OK (or maybe a redirect, depends on your expected outcome) and it will tell you that a file exists.

Only download files if you are actually going to do something with them, if you are downloading them for the sake of doing it you are wasting test time, network bandwidth and disk space.

Here is my implementation:

https://github.com/Ardesco/Ebselen/blob/master/ebselen-core/src/main/java/com/lazerycode/ebselen/customhandlers/FileDownloader.java

This finds the link on the page and extracts the url being linked to. It then uses apache commons to replicate the browser session used by selenium and then download the file. There are some instances where it won't work (where the link found on the page does not actually link to the download file but a layer to prevent automated file download).

Generally it works well and is cross platform/cross browser complient.

The code is:

 /*
* Copyright (c) 2010-2011 Ardesco Solutions - http://www.ardescosolutions.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.lazerycode.ebselen.customhandlers;

import com.google.common.annotations.Beta;
import com.lazerycode.ebselen.EbselenCore;
import com.lazerycode.ebselen.handlers.FileHandler;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;

import java.io.*;
import java.net.URL;
import java.util.Set;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Beta
public class FileDownloader {

    private static final Logger LOGGER = LoggerFactory.getLogger(EbselenCore.class);
    private WebDriver driver;
    private String downloadPath = System.getProperty("java.io.tmpdir");

    public FileDownloader(WebDriver driverObject) {
        this.driver = driverObject;
    }

    /**
* Get the current location that files will be downloaded to.
*
* @return The filepath that the file will be downloaded to.
*/
    public String getDownloadPath() {
        return this.downloadPath;
    }

    /**
* Set the path that files will be downloaded to.
*
* @param filePath The filepath that the file will be downloaded to.
*/
    public void setDownloadPath(String filePath) {
        this.downloadPath = filePath;
    }


    /**
* Load in all the cookies WebDriver currently knows about so that we can mimic the browser cookie state
*
* @param seleniumCookieSet
* @return
*/
    private HttpState mimicCookieState(Set<org.openqa.selenium.Cookie> seleniumCookieSet) {
        HttpState mimicWebDriverCookieState = new HttpState();
        for (org.openqa.selenium.Cookie seleniumCookie : seleniumCookieSet) {
            Cookie httpClientCookie = new Cookie(seleniumCookie.getDomain(), seleniumCookie.getName(), seleniumCookie.getValue(), seleniumCookie.getPath(), seleniumCookie.getExpiry(), seleniumCookie.isSecure());
            mimicWebDriverCookieState.addCookie(httpClientCookie);
        }
        return mimicWebDriverCookieState;
    }

    /**
* Mimic the WebDriver host configuration
*
* @param hostURL
* @return
*/
    private HostConfiguration mimicHostConfiguration(String hostURL, int hostPort) {
        HostConfiguration hostConfig = new HostConfiguration();
        hostConfig.setHost(hostURL, hostPort);
        return hostConfig;
    }

    public String fileDownloader(WebElement element) throws Exception {
        return downloader(element, "href");
    }

    public String imageDownloader(WebElement element) throws Exception {
        return downloader(element, "src");
    }

    public String downloader(WebElement element, String attribute) throws Exception {
        //Assuming that getAttribute does some magic to return a fully qualified URL
        String downloadLocation = element.getAttribute(attribute);
        if (downloadLocation.trim().equals("")) {
            throw new Exception("The element you have specified does not link to anything!");
        }
        URL downloadURL = new URL(downloadLocation);
        HttpClient client = new HttpClient();
        client.getParams().setCookiePolicy(CookiePolicy.RFC_2965);
        client.setHostConfiguration(mimicHostConfiguration(downloadURL.getHost(), downloadURL.getPort()));
        client.setState(mimicCookieState(driver.manage().getCookies()));
        HttpMethod getRequest = new GetMethod(downloadURL.getPath());
        FileHandler downloadedFile = new FileHandler(downloadPath + downloadURL.getFile().replaceFirst("/|\\\\", ""), true);
        try {
            int status = client.executeMethod(getRequest);
            LOGGER.info("HTTP Status {} when getting '{}'", status, downloadURL.toExternalForm());
            BufferedInputStream in = new BufferedInputStream(getRequest.getResponseBodyAsStream());
            int offset = 0;
            int len = 4096;
            int bytes = 0;
            byte[] block = new byte[len];
            while ((bytes = in.read(block, offset, len)) > -1) {
                downloadedFile.getWritableFileOutputStream().write(block, 0, bytes);
            }
            downloadedFile.close();
            in.close();
            LOGGER.info("File downloaded to '{}'", downloadedFile.getAbsoluteFile());
        } catch (Exception Ex) {
            LOGGER.error("Download failed: {}", Ex);
            throw new Exception("Download failed!");
        } finally {
            getRequest.releaseConnection();
        }
        return downloadedFile.getAbsoluteFile();
    }
}
share|improve this answer
    
Just curious, will that work for HTTPS? I guess no, as there is no support for SSL in your HttpClient configuration... –  dzieciou Jun 28 at 17:51
    
It should work (hc.apache.org/httpclient-3.x/sslguide.html), but the http client library is now EOL so you are better off using the HTTP Component library hc.apache.org/httpcomponents-client-ga/examples.html –  Ardesco Jun 30 at 6:31

Here's a solution. Set Firefox's preferences to save automatically, and not have the downloads window popup. Then you just grab the file, and it'll download.

So, something like this:

    FirefoxProfile fxProfile = new FirefoxProfile();

    fxProfile.setPreference("browser.download.folderList",2);
    fxProfile.setPreference("browser.download.manager.showWhenStarting",false);
    fxProfile.setPreference("browser.download.dir","c:\\mydownloads");
    fxProfile.setPreference("browser.helperApps.neverAsk.saveToDisk","text/csv");

    WebDriver driver = new FirefoxDriver(fxProfile);
    driver.navigate().to("http://www.foo.com/bah.csv");

and given you now have the download directory, never ask to save, and no download manager appearing, automation from this point should be straightforward.

share|improve this answer
    
Worked like a charm, but I used my user profile. stackoverflow.com/questions/15954682/… –  jmunsch Apr 27 at 23:13

How about this approach:

How to auto save files using custom Firefox profile?

share|improve this answer
    
Cross platform and Python. This is the best approach. –  Cerin Oct 29 '12 at 12:06

This blog post describes a straight forward way of invoking another library to download the file (so not through the browser) whilst maintaining selenium's session with the site - so it works on password-protected files, etc.

share|improve this answer
    
I have realised this is similar to Ardesco's answer. However, I think the solution in the blog post is simpler. Also, it is for .NET rather than Java, so it may be useful to people targeting that platform. –  Martin Eden Jun 11 '12 at 17:21
    
Windows only? Blargh. –  Cerin Oct 29 '12 at 12:03

The best way I have found to do this is by accessing the page, getting the download link, and performing a HEAD request for the file with an HTTP library. The response will contain the length of the file and it's type.

A HEAD request is preferable since it will only retrieve the headers instead of pulling down the entire file.

And if the file is behind auth, you will need to pull the session cookie from Selenium's cookie store and pass it into the HTTP library when performing the request.

That, or you can configure the browser you're using to auto-download files to a specific location and then perform checks against the file on disk.

I've outlined each of these approaches in detail with working Ruby code here:

Cheers,
Dave H
@TourDeDave

share|improve this answer

First, think about - do you really need to download an image? Or You just need to make sure that it exists and it is able to be downloaded?

Here you may find full trusted description how to check that image is available and exists, just by following by image's URL.

Main steps are:

  • extract authorization cookies (if user session required)
  • use them for building new HTTP request
  • send such request with image's URL to check status code
  • if status code is 200 - image exists
  • To get webDriver-like cookies just use something like that:

    webDriver.manage().getCookieNamed("JSESSIONID");
    

    Note, that it is not apache-like cookies, you can not use them strictly with apache http client. But you could build one apache-like based on it.

    share|improve this answer
        
    welcome to sqa.stackexchange.com. This is a nicely detailed answer but the OP was pretty clear about wanting to download a document vs checking an image. The answers are most effective when the address the question asked. –  Dan Snell Feb 20 '13 at 23:21
        
    Sorry! :))) I was so attracted by searching for approaches about how to check that image exists that focused on it too much and miss "document". Ok, anyway - download file should be quite the same, I think. Thanks for comment –  Gadget Feb 21 '13 at 8:12

    An approach that I took I took recently to this was to capture to response via fiddler. In my case I am making a call directly to the export handler in our application. I have wrapped the selenium bits and intercepted the traffic with fiddler core. I actually just cared about the data in the file not that the browser correctly interpreted the request. You could also accomplish this using the a click action as well

            static string Test2ExportGeneration()
        {
            IWebDriver driver = new InternetExplorerDriver();
            FiddlerApplication.Startup(8877, true, true);
    
            List<Session> oAllSessions = new List<Session>();
    
            LoginPage login = new LoginPage(driver);
            //PerformancePage perf = new PerformancePage(driver);
    
            FiddlerApplication.AfterSessionComplete += delegate(Session oS)
            {
                Monitor.Enter(oAllSessions);
                oAllSessions.Add(oS);
                Monitor.Exit(oAllSessions);
            };
    
            driver.Navigate().GoToUrl(test2BaseURL + "login.aspx");
            login.LoginToView("test123@test123.com", "pw");
            driver.Navigate().GoToUrl(test2BaseURL + "/handlers/export.ashx?id=74&accountId=164");
    
            FiddlerApplication.Shutdown();
    
            driver.Quit();
            string responseBody = "";
    
            foreach (Session oS in oAllSessions)
            {
                if (oS.fullUrl.Contains("handlers"))
                {
                    oS.utilDecodeResponse();
                    string type = oS.oResponse.MIMEType;
    
                    responseBody = oS.GetResponseBodyAsString();
    
                }
            }
    
            return responseBody;
    
        }
    

    The GetResponseBodyAsString() method in FiddlerCore unpacks the response and returns a string I can then manipulate and work with in code.

    I am using C# and webdriver for my implementation. If you are using a different language I think there are some other tools as well. I my opinion the advantage of this is that I can strip away having to try to interact with the file download mechanisms of any of the browsers. If I want to create the file later all of the information the browser would have received is in the response header.

    share|improve this answer

    A simple but somewhat flimsy solution (depending on whether you're expecting a consistent screen size in your target environment); is to use the java.awt.Robot class as below.. You could also try the chromedriver for selenium; as I've noticed chrome doesn't have an OS dialogue for download confirmation.

    //add wait time to for file download dialogue to appear
        Sleeper.SYSTEM_SLEEPER.sleep(new Duration(5,java.util.concurrent.TimeUnit.SECONDS));
        Robot r = new Robot();
        r.mouseMove(888, 458);//coordinates of save button
        //focus dialogue window
        r.mousePress(InputEvent.BUTTON1_MASK);
        r.mouseRelease(InputEvent.BUTTON1_MASK);
        Sleeper.SYSTEM_SLEEPER.sleep(new Duration(1,java.util.concurrent.TimeUnit.SECONDS));
        //click save button
        r.mousePress(InputEvent.BUTTON1_MASK);
        r.mouseRelease(InputEvent.BUTTON1_MASK);
        //wait for file to download
        Sleeper.SYSTEM_SLEEPER.sleep(new Duration(5,java.util.concurrent.TimeUnit.SECONDS));
    
    share|improve this answer

    Your Answer

     
    discard

    By posting your answer, you agree to the privacy policy and terms of service.

    Not the answer you're looking for? Browse other questions tagged or ask your own question.