selenoid icon indicating copy to clipboard operation
selenoid copied to clipboard

How to download a file using a chrome browser without opening download file dialog box

Open PingleSneha opened this issue 5 years ago • 15 comments

Hi. I am trying to download a file and verify its contents using chrome browser. Below are my chrome options i am trying to use, with these options the download file dialog box opens and my test script fails. I am looking out for chrome and firefox options to suppress download file dialog box and proceed with file download.

ChromeOptions -

String path = "home" + File.separator + "selenium" + File.separator + "Downloads" + File.separator; System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir") + File.separator + "lib" + File.separator + "chromedriver.exe"); System.setProperty("webdriver.chrome.verboseLogging", "true"); System.setProperty(ChromeDriverService.CHROME_DRIVER_LOG_PROPERTY, System.getProperty("user.dir") + File.separator + "log" + File.separator + "chrome.log");

HashMap<String, Object> chromePrefs = new HashMap<String, Object>();
chromePrefs.put("profile.default_content_settings.popups", 2);
chromePrefs.put("profile.default_content_settings.javascript", 1);
chromePrefs.put("download.default_directory", path);
chromePrefs.put("credentials_enable_service",false);
chromePrefs.put("download.prompt_for_download", false);
chromePrefs.put("profile.content_settings.exceptions.automatic_downloads.*.setting", 1);
chromePrefs.put("safebrowsing.enabled", true);

ChromeOptions options = new ChromeOptions();
options.setExperimentalOption("excludeSwitches", new String[] { "enable-automation" });
options.setExperimentalOption("forceDevToolsScreenshot", true);
options.setExperimentalOption("useAutomationExtension", false);
options.setExperimentalOption("detach", false);
options.setExperimentalOption("prefs", chromePrefs);

options.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
options.setCapability("enableVNC", true);
options.setCapability("version", "67.0");

options.addArguments("--disable-infobars"); 
options.addArguments("--test-type"); 
options.addArguments("--disable-extensions");
options.addArguments("--ignore-certificate-errors");
options.addArguments("--enable-javascript");
options.addArguments("--start-maximized", "--window-size=1360,1020");

PingleSneha avatar May 15 '19 06:05 PingleSneha

@PingleSneha your approach seems to be correct. What is not working?

vania-pooh avatar May 15 '19 09:05 vania-pooh

The file is not getting downloaded. It is stuck at file download dialog box. I am intending to download this file without this dialog box open

PingleSneha avatar May 15 '19 10:05 PingleSneha

@PingleSneha in case anyone is curious, my settings below allowed me to download w/o the prompt showing:

chromePrefs.put("profile.default_content_settings.popups", 0);
chromePrefs.put("profile.default_content_setting_values.automatic_downloads",1);
chromePrefs.put("download.default_directory", "/home/selenium/Downloads");

timothyjmtan avatar Jan 23 '20 03:01 timothyjmtan

@PingleSneha we had the same issue and successfully resolved it. Here our chrome config (in Protractor):

'goog:chromeOptions': {
      prefs: {
        download: {
          prompt_for_download: false,
          directory_upgrade: true,
          default_directory: downloadsDirectory
        },
        profile: {
          default_content_settings: {
            popups: 0
          },
          default_content_setting_values: {
            automatic_downloads: 1
          }
        },
        safebrowsing: {
          enabled: false
        },
        plugins: {
          plugins_disabled: false
        }
      }

Where the most interesting part is 'downloadsDirectory'. If you are running tests on Selenoid - you should provide '/home/selenium/Downloads', if you are running locally - you need to have already existent directory and to provide a path to it like ${process.cwd()}/downloads. If you need to check something in file which was downloaded while running test on Selenoid instance, you need at first to get its link by session ID and download it from remote Selenoid container to the machine where test framework was launched. Link to the file is like that:

const selenoidDownloadsLink = `https://${browser.params.selenoidHost}:${browser.params.selenoidPort}/download/${sessionID}`;
fileName = await element(by.tagName('a')).getText();
const fileUrl = `${selenoidDownloadsLink}/${fileName}`;

And you just need to download it to the framework's machine and do whatever you want to do with it (we are checking for example that xlsx file has expected data inside). FYI: If download directory in capabilities for Selenoid configured in not correct way - you will see your issue with download dialog instead of automatic file downloading.

viktorgogulenko avatar May 26 '20 21:05 viktorgogulenko

Hi @viktorgogulenko, Can you help with the similar requirement below - A zip file is downloading and given "default_directory": "/home/selenium/Downloads" in chrome options and I see in the vnc viewer that the zip file is downloading. My requirement is : Need to copy the downloaded zip file into my local framework path.

If can you provide a code snippet for this is a great help. Thanks

Mypaal7 avatar Oct 06 '20 06:10 Mypaal7

@Mypaal7 Here is a snippet to be able to handle both scenarios: if tests are running on Selenoid side or using local browser:

async downloadFile(url, downloadDestinationPath) {
    await download(url, downloadDestinationPath);
  },

  async getPathToDownloadedFile() {
    let fileName;
    let filePath;
    const sessionId = await browser.getSession().then((sessionData => sessionData.id_));
    const address = await browser.getProcessedConfig().then(config => config.seleniumAddress);
    // Download file from Selenoid if it was used as seleniumAddress
    if (address === `https://${browser.params.selenoidHost}:${browser.params.selenoidPort}/wd/hub/`) {
      const pdfLocalDownloadsFolder = `${localDownloadsFolder}/${sessionId}`;
      await fsAsync.mkdir(pdfLocalDownloadsFolder, { recursive: true }, (err) => {
        if (err) {
          // eslint-disable-next-line no-console
          console.log(err);
        } else {
          // eslint-disable-next-line no-console
          console.log('New directory successfully created.');
        }
      });
      const selenoidDownloadsLink = `https://${browser.params.selenoidHost}:${browser.params.selenoidPort}/download/${sessionId}`;
      await browser.get(selenoidDownloadsLink);
      // Go to Webpage of Selenoid downloads and get a filename of downloaded file
      await browser.get(selenoidDownloadsLink);
      fileName = await element(by.tagName('a')).getText();
      // Download file from remote Selenoid container to local machine
      const fileUrl = `${selenoidDownloadsLink}/${fileName}`;
      await this.downloadFile(fileUrl, pdfLocalDownloadsFolder);
      filePath = `${localDownloadsFolder}/${sessionId}/${fileName}`;
      return filePath;
    }
    // in case of local run using local browser
    filePath = glob.sync(`${localDownloadsFolder}/*.*`)
      .map(name => ({ name, ctime: fs.statSync(name).ctime }))
      .sort((a, b) => b.ctime - a.ctime)[0].name;
    return filePath;
  },

and after that you can do whatever you need with path to the file (open, read, etc.) Maybe there are some more "elegant" solutions, but this one is totally working for us.

viktorgogulenko avatar Oct 06 '20 06:10 viktorgogulenko

@viktorgogulenko Thanks for this code, but still I am facing the issue - {browser.params.selenoidHost} and ${browser.params.selenoidPort} returniung 'undefined' and so avoid this I just updated the code as below - async function getPathToDownloadedFile(localDownloadsFolder) { let fileName; let filePath; const sessionId = await browser.getSession().then((sessionData) => sessionData.id_); const address = await browser.getProcessedConfig().then((config) => config.seleniumAddress); logger.info(sessionId & addres ::${sessionId} \n ${address}); logger.info(actual adress addres :: http://${browser.params.selenoidHost}:${browser.params.selenoidPort}/wd/hub/ ==== ${address}); if (address === "http://localhost:4444/wd/hub/") { const selenoidDownloadsLink = http://localhost:4444/download/${sessionId};

    await browser.get(selenoidDownloadsLink);
    await browser.get(selenoidDownloadsLink);
    fileName = await element(by.tagName("a")).getText();
    const fileUrl = `${selenoidDownloadsLink}/${fileName}`;

    logger.info(`Selenoid file path ::${fileUrl}`);
    filePath = `${localDownloadsFolder}/${sessionId}/${fileName}`;
    logger.info(`local file path ::${filePath}`);

    return filePath;
}

}

Please suggest, thanks !

Mypaal7 avatar Oct 06 '20 11:10 Mypaal7

Just for clarification:

const address = await browser.getProcessedConfig().then(config => config.seleniumAddress);

^^ here we are getting selenium address from protractor.conf.js file. In case of Selenoid, selenium address is something like:

const selenoidHost = 'your.selenoid.server.com';
const selenoidPort = '5443';

seleniumAddress: `https://${selenoidHost}:${selenoidPort}/wd/hub/`

and here we are checking that if seleniumAddress is equals to selenoid address from protractor.conf.js, execute that actions inside of "if", else just download to "download" folder in your test project and take the latest filename path from it for further actions.

Also in protractor.conf.js we provided folders for each of cases (for local run and on selenoid):

const localDownloadsFolder = `${process.cwd()}/downloads`;
const downloadsFolderOnSelenoid = '/home/selenium/Downloads';

P.S. we are running our tests in way "1 scenario - 1 "it"", so on one selenoid browser container only one test will be executed to avoid conflicts and also to speed up tests for running in parallel. So in selenoid one browser session will be only 1 downloaded file available.

viktorgogulenko avatar Oct 06 '20 11:10 viktorgogulenko

@viktorgogulenko My selenium adress is - http://localhost:4444/wd/hub/ so given static value.

  1. Also i am running tests on Selenoid container only. not running locally any.
  2. Given downloaded path in the protractor.conf.js - '/home/selenium/Downloads'
  3. const selenoidDownloadsLink = http://localhost:4444/download/${sessionId}; // http://localhost:4444/download/335fdd6ae7779141722fc51d94b3865e await browser.get(selenoidDownloadsLink); this is throwing an error that Screenshot 2020-10-06 at 5 18 39 PM

Mypaal7 avatar Oct 06 '20 11:10 Mypaal7

@viktorgogulenko This is kind of a blocker for me, so if any help would be greatly appreciated

Mypaal7 avatar Oct 06 '20 14:10 Mypaal7

any update on the solution for this? now I facing the same issue when downloading a file the download file dialog will be displayed, with config below its work well in local but cannot work in Selenoid

Map<String, Object> chromePrefs = new HashMap<>();
chromePrefs.put("profile.default_content_settings.popups", 2);
chromePrefs.put("profile.default_content_settings.javascript", 1);
chromePrefs.put("download.default_directory", SCREENSHOT_PATH);
chromePrefs.put("credentials_enable_service",false);
chromePrefs.put("download.prompt_for_download", false);
chromePrefs.put("profile.content_settings.exceptions.automatic_downloads.*.setting", 1);
chromePrefs.put("safebrowsing.enabled", true);
chromeOptions.setExperimentalOption("prefs", chromePrefs);

Screen Shot 2021-11-11 at 19 09 00

KevinLuc95 avatar Nov 11 '21 12:11 KevinLuc95

I was able to resolve the problem, seem like selenoid just accept the path /home/selenium/Downloads

KevinLuc95 avatar Nov 15 '21 00:11 KevinLuc95

@KevinLuc95 yes, because user name for browser images is selenium and default download directory is ~/Downloads.

vania-pooh avatar Nov 15 '21 03:11 vania-pooh

I was able to resolve the problem, seem like selenoid just accept the path /home/selenium/Downloads

How did you do that? can you help me please. Thanks.

eaguerrerov avatar Jul 29 '23 00:07 eaguerrerov

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] avatar Feb 06 '24 01:02 github-actions[bot]