Skip to content

Commit 8cb42e9

Browse files
kobenguyentDavertMik
authored andcommitted
adding downloadFile action for puppeteer (#1542)
* adding downloadFile action for puppeteer * CR addressed * fixed tests * lint fixed * debug * removed .only from describe * fixed failed test * lint fixed
1 parent 15a5456 commit 8cb42e9

4 files changed

Lines changed: 124 additions & 0 deletions

File tree

docs/helpers/Puppeteer.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,21 @@ I.doubleClick('.btn.edit');
470470
- `locator` clickable link or button located by text, or any element located by CSS|XPath|strict locator.
471471
- `context` (optional) element to search in CSS|XPath|Strict locator.
472472

473+
### downloadFile
474+
475+
Performs a download file on an element matched by link|button|CSS or XPath.
476+
File is downloaded by default to output folder.
477+
If no custom file name is provided, the default name will be used
478+
479+
```js
480+
I.downloadFile('td[class="text-right file-link"] a', 'thisIsCustomName');
481+
```
482+
483+
#### Parameters
484+
485+
- `locator` clickable link or button located by CSS|XPath locator.
486+
- `string` custom file name.
487+
473488
### dragAndDrop
474489

475490
Drag an item to a destination element.

docs/webapi/downloadFile.mustache

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Performs a download file on an element matched by link|button|CSS or XPath.
2+
File is downloaded by default to output folder.
3+
If no custom file name is provided, the default name will be used
4+
5+
6+
```js
7+
I.downloadFile('td[class="text-right file-link"] a', 'thisIsCustomName');
8+
```
9+
10+
@param locator clickable link or button located by CSS|XPath locator.
11+
@param string custom file name.

lib/helper/Puppeteer.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ const ElementNotFound = require('./errors/ElementNotFound');
2525
const RemoteBrowserConnectionRefused = require('./errors/RemoteBrowserConnectionRefused');
2626
const Popup = require('./extras/Popup');
2727
const Console = require('./extras/Console');
28+
const axios = require('axios');
29+
const fs = require('fs');
2830

2931

3032
let puppeteer;
@@ -851,6 +853,55 @@ class Puppeteer extends Helper {
851853
return proceedClick.call(this, locator, context, { waitForNavigation: true });
852854
}
853855

856+
/**
857+
* {{> ../webapi/downloadFile }}
858+
*/
859+
async downloadFile(locator, customName) {
860+
let fileName;
861+
await this.page.setRequestInterception(true);
862+
this.click(locator);
863+
864+
const xRequest = await new Promise((resolve) => {
865+
this.page.on('request', (request) => {
866+
const grabbedFileName = request.url().split('/')[request.url().split('/').length - 1];
867+
const fileExtension = request.url().split('/')[request.url().split('/').length - 1].split('.')[1];
868+
customName ? fileName = `${customName}.${fileExtension}` : fileName = grabbedFileName;
869+
request.abort();
870+
resolve(request);
871+
});
872+
});
873+
874+
const options = {
875+
encoding: null,
876+
method: xRequest._method,
877+
uri: xRequest._url,
878+
body: xRequest._postData,
879+
headers: xRequest._headers,
880+
};
881+
882+
const cookies = await this.page.cookies();
883+
options.headers.Cookie = cookies.map(ck => `${ck.name}=${ck.value}`).join(';');
884+
885+
const response = await axios({
886+
method: options.method, url: options.uri, headers: options.headers, responseType: 'arraybuffer',
887+
});
888+
889+
const outputFile = path.join(`${global.output_dir}/${fileName}`);
890+
891+
try {
892+
return new Promise((resolve, reject) => {
893+
const wstream = fs.createWriteStream(outputFile);
894+
wstream.write(response.data);
895+
wstream.end();
896+
this.debug(`File is downloaded in ${outputFile}`);
897+
wstream.on('finish', () => { resolve(fileName); });
898+
wstream.on('error', reject);
899+
});
900+
} catch (error) {
901+
throw new Error(`There is something wrong with downloaded file. ${error}`);
902+
}
903+
}
904+
854905
/**
855906
* {{> ../webapi/doubleClick }}
856907
*/

test/helper/Puppeteer_test.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ const AssertionFailedError = require('../../lib/assert/error');
1010
const formContents = require('../../lib/utils').test.submittedData(path.join(__dirname, '/../data/app/db'));
1111
const expectError = require('../../lib/utils').test.expectError;
1212
const webApiTests = require('./webapi');
13+
const FileSystem = require('../../lib/helper/FileSystem');
1314

1415
let I;
1516
let browser;
1617
let page;
18+
let FS;
1719
const siteUrl = TestHelper.siteUrl();
1820

1921
describe('Puppeteer', function () {
@@ -22,6 +24,7 @@ describe('Puppeteer', function () {
2224

2325
before(() => {
2426
global.codecept_dir = path.join(__dirname, '/../data');
27+
2528
I = new Puppeteer({
2629
url: siteUrl,
2730
windowSize: '500x700',
@@ -558,6 +561,50 @@ describe('Puppeteer', function () {
558561
assert.notEqual(before, after);
559562
});
560563
});
564+
565+
describe('#downloadFile', () => {
566+
before(() => {
567+
// create download folder;
568+
fs.mkdir(path.join(`${__dirname}/../data/download`), () => {
569+
570+
});
571+
global.output_dir = path.join(`${__dirname}/../data/download`);
572+
573+
FS = new FileSystem();
574+
FS._before();
575+
FS.amInPath('download');
576+
});
577+
578+
after(() => {
579+
// Remove the test dir
580+
fs.readdir(global.output_dir, (err, files) => {
581+
if (err) throw err;
582+
583+
for (const file of files) {
584+
if (file.includes('.mp4')) {
585+
fs.unlink(path.join(global.output_dir, file), (err) => {
586+
if (err) throw err;
587+
});
588+
}
589+
}
590+
});
591+
});
592+
593+
594+
it('should dowload file', async () => {
595+
await I.amOnPage('http://file-examples.com/index.php/sample-video-files/sample-mp4-files/');
596+
const fileName = await I.downloadFile('td[class="text-right file-link"] a');
597+
598+
FS.seeFile(fileName);
599+
});
600+
601+
it('should dowload file with custom name', async () => {
602+
await I.amOnPage('http://file-examples.com/index.php/sample-video-files/sample-mp4-files/');
603+
const fileName = await I.downloadFile('td[class="text-right file-link"] a', 'thisisacustomname');
604+
605+
FS.seeFile(fileName);
606+
});
607+
});
561608
});
562609

563610
let remoteBrowser;

0 commit comments

Comments
 (0)