Tell me more ×
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 mostly 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

5 Answers

up vote 2 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 Shaver Dec 2 '11 at 22:05

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

How about this approach ? http://selenium-python.readthedocs.org/en/latest/faq.html#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

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 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 at 8:12

    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.