How to probe if a file was download using Selenium

2019-09-21 06:58发布

问题:

I want to know how I can verify if a file was downloaded using Selenium Webdriver after I click the download button.

回答1:

Your question doesn't say whether you want to confirm it locally or remotely(like browserstack) . If it is remotely then my answer will be "NO" as you can see that the file is getting downloaded but you can not access the folder. So you wont be able to assert that the file has been downloaded.

If you want to achieve this locally(in Chrome) then the answer is "YES", you can do it something like this:

In wdio.conf.js(To know where it is getting downloaded)

var path = require('path');

const pathToDownload = path.resolve('chromeDownloads');

// chromeDownloads above is the name of the folder in the root directory
exports.config = {
capabilities: [{
        maxInstances: 1,     
        browserName: 'chrome',
        os: 'Windows',      
        chromeOptions: {
            args: [
                'user-data-dir=./chrome/user-data',
            ],
            prefs: {
                "download.default_directory": pathToDownload,
            }
        }
    }],

And your spec file(To check if the file is downloaded or not ?)

const fsExtra = require('fs-extra');
const pathToChromeDownloads = './chromeDownloads';

describe('User can download and verify a file', () =>{

    before(() => {
        // Clean up the chromeDownloads folder and create a fresh one
        fsExtra.removeSync(pathToChromeDownloads);
        fsExtra.mkdirsSync(pathToChromeDownloads);
    });

    it('Download the file', () =>{
        // Code to download 
    });

    it('Verify the file is downloaded', () =>{
        // Code to verify 
        // Get the name of file and assert it with the expected name
    });
});

more about fs-extra : https://www.npmjs.com/package/fs-extra

Hope this helps.



回答2:

TL;DR: Unless your web-app has some kind of visual/GUI trigger once the download finishes (some text, an image/icon-font, push-notification, etc.), then the answer is a resounding NO.

Webdriver can't go outside the scope of your browser, but your underlying framework can. Especially if you're using NodeJS. :)

Off the top of my head I can think of a few ways I've been able to do this in the past. Choose as applicable:

1. Verify if the file has been downloaded using Node's File System (aka fs)

Since you're running WebdriverIO, under a NodeJS environment, then you can make use its powerful lib tool-suite. I would use fs.exists, or fs.existsSync to verify if the file is in the expected folder.

If you want to be diligent, then also use fs.statSync in conjunction with fs.exists & poll the file until it has the expected size (e.g.: > 2560 bytes)

There are multiple examples online that can help you put together such a script. Use the fs documentation, but other resources as well. Lastly, you can add said script inside your it/describe statement (I remember your were using Mocha).

2. Use child_process's exec command to launch third-party scripts

Though this method requires more work to setup, I find it more relevant on the long run.

!!! Caution: Apart from launching the script, you need to write a script in a third-party framework.

  • Using an AutoIT script;
  • Using a Sikuli script;
  • Using a TestComplete (not linking it, I don't like it that much), or [insert GUI verification script here] script;

Note: All the above frameworks can generate an .exe file that you can trigger from your WebdriverIO test-cases in order to check if your file has been downloaded, or not.

Steps to take:

  • create one of the stand-alone scripts like mentioned above;
  • place the script's .exe file inside your project in a known folder;
  • use child_process.exec to launch the script and assert its result after it finishes its execution;

Example:

exec = require('child_process').exec;
// Make sure you also remove the .exe from scriptName
var yourScript = pathToScript + scriptName;

var child = exec(yourScript); 
child.on('close', function (code, signal) {
    if (code!==0) {
        callback.fail(online.online[module][code]);
    } else {
        callback();
    } 
});

Finally: I'm sure there are other ways to do it. But, your main take-away from such a vague question should be: YES, you can verify if the file has been downloaded if you absolutely must, expecially if this test-case is CRITICAL to your regression-run.