From 85966f969f89a63e4f933f344bc3a5e01752541d Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Tue, 5 Mar 2019 16:35:01 +0100 Subject: [PATCH 1/8] adding downloadFile action for puppeteer --- docs/helpers/Puppeteer.md | 13 +++++++++ docs/webapi/downloadFile.mustache | 9 ++++++ lib/command/definitions.js | 4 +-- lib/helper/Puppeteer.js | 46 +++++++++++++++++++++++++++++++ lib/parser.js | 2 +- lib/utils.js | 2 +- test/helper/Puppeteer_test.js | 28 +++++++++++++++++++ 7 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 docs/webapi/downloadFile.mustache diff --git a/docs/helpers/Puppeteer.md b/docs/helpers/Puppeteer.md index f5421f52e..9a8a232b1 100644 --- a/docs/helpers/Puppeteer.md +++ b/docs/helpers/Puppeteer.md @@ -470,6 +470,19 @@ I.doubleClick('.btn.edit'); - `locator` clickable link or button located by text, or any element located by CSS|XPath|strict locator. - `context` (optional) element to search in CSS|XPath|Strict locator. +### downloadFile + +Performs a download file on an element matched by link|button|CSS or XPath. +File is downloaded by default to output folder + +```js +I.downloadFile('td[class="text-right file-link"] a'); +``` + +#### Parameters + +- `locator` clickable link or button located by CSS|XPath locator. + ### dragAndDrop Drag an item to a destination element. diff --git a/docs/webapi/downloadFile.mustache b/docs/webapi/downloadFile.mustache new file mode 100644 index 000000000..1744f5f9f --- /dev/null +++ b/docs/webapi/downloadFile.mustache @@ -0,0 +1,9 @@ +Performs a download file on an element matched by link|button|CSS or XPath. +File is downloaded by default to output folder + + +```js +I.downloadFile('td[class="text-right file-link"] a'); +``` + +@param locator clickable link or button located by CSS|XPath locator. \ No newline at end of file diff --git a/lib/command/definitions.js b/lib/command/definitions.js index 96b1afdd9..fdfd5eeae 100644 --- a/lib/command/definitions.js +++ b/lib/command/definitions.js @@ -206,9 +206,9 @@ module.exports = function (genPath, options) { function addAllMethodsInObject(supportObj, actions, methods, translations) { for (const action of methodsOfObject(supportObj)) { - let fn = supportObj[action]; + const fn = supportObj[action]; if (!fn.name) { - Object.defineProperty(fn, "name", {value: action}); + Object.defineProperty(fn, 'name', { value: action }); } const actionAlias = translations ? translations.actionAliasFor(action) : action; if (!actions[actionAlias]) { diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index 98451ab83..cef4e79ea 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -25,6 +25,8 @@ const ElementNotFound = require('./errors/ElementNotFound'); const RemoteBrowserConnectionRefused = require('./errors/RemoteBrowserConnectionRefused'); const Popup = require('./extras/Popup'); const Console = require('./extras/Console'); +const axios = require('axios'); +const fs = require('fs'); let puppeteer; @@ -851,6 +853,50 @@ class Puppeteer extends Helper { return proceedClick.call(this, locator, context, { waitForNavigation: true }); } + /** + * {{> ../webapi/downloadFile }} + */ + async downloadFile(locator) { + let fileName; + await this.page.setRequestInterception(true); + this.click(locator); + + const xRequest = await new Promise((resolve) => { + this.page.on('request', (request) => { + fileName = request.url().split('/')[request.url().split('/').length - 1]; + request.abort(); + resolve(request); + }); + }); + + const options = { + encoding: null, + method: xRequest._method, + uri: xRequest._url, + body: xRequest._postData, + headers: xRequest._headers, + }; + + const cookies = await this.page.cookies(); + options.headers.Cookie = cookies.map(ck => `${ck.name}=${ck.value}`).join(';'); + + const response = await axios({ + method: options.method, url: options.uri, headers: options.headers, responseType: 'arraybuffer', + }); + + const outputFile = path.join(`${global.output_dir}/${fileName}`); + + try { + const wstream = fs.createWriteStream(outputFile); + wstream.write(response.data); + wstream.end(); + this.debug(`File is downloaded in ${outputFile}`); + return outputFile; + } catch (error) { + throw new Error(`There is something wrong with downloaded file. ${error}`); + } + } + /** * {{> ../webapi/doubleClick }} */ diff --git a/lib/parser.js b/lib/parser.js index 7583eb050..99eaa4460 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -87,7 +87,7 @@ function getParams(fn) { }); return params; } catch (err) { - console.log('Error in ' + newFn.toString()); + console.log(`Error in ${newFn.toString()}`); console.error(err); } } diff --git a/lib/utils.js b/lib/utils.js index 1f02abd7c..9b6b5c28e 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -40,7 +40,7 @@ const isGenerator = module.exports.isGenerator = function (fn) { }; const isFunction = module.exports.isFunction = function (fn) { - return typeof fn === 'function' + return typeof fn === 'function'; }; const isAsyncFunction = module.exports.isAsyncFunction = function (fn) { diff --git a/test/helper/Puppeteer_test.js b/test/helper/Puppeteer_test.js index cf9b887a7..49b3b9b1a 100644 --- a/test/helper/Puppeteer_test.js +++ b/test/helper/Puppeteer_test.js @@ -22,6 +22,12 @@ describe('Puppeteer', function () { before(() => { global.codecept_dir = path.join(__dirname, '/../data'); + // create directory /download; + fs.mkdir(path.join(`${__dirname}/download`), () => { + + }); + global.output_dir = path.join(`${__dirname}/download`); + I = new Puppeteer({ url: siteUrl, windowSize: '500x700', @@ -51,6 +57,19 @@ describe('Puppeteer', function () { return I._after(); }); + after(() => { + // Remove the test dir + fs.readdir(global.output_dir, (err, files) => { + if (err) throw err; + + for (const file of files) { + fs.unlink(path.join(global.output_dir, file), (err) => { + if (err) throw err; + }); + } + }); + }); + describe('open page : #amOnPage', () => { it('should open main page of configured site', async () => { await I.amOnPage('/'); @@ -558,6 +577,15 @@ describe('Puppeteer', function () { assert.notEqual(before, after); }); }); + + describe.only('#downloadFile', () => { + it('should dowload file', async () => { + await I.amOnPage('http://file-examples.com/index.php/sample-video-files/sample-mp4-files/'); + const outputFile = await I.downloadFile('td[class="text-right file-link"] a'); + + assert.equal(fs.existsSync(path.join(outputFile)), true); + }); + }); }); let remoteBrowser; From 6a15a541bfd0c48584a12ee0fffc5141942bf459 Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Wed, 6 Mar 2019 11:27:43 +0100 Subject: [PATCH 2/8] CR addressed --- docs/helpers/Puppeteer.md | 6 ++++-- docs/webapi/downloadFile.mustache | 8 +++++--- lib/helper/Puppeteer.js | 8 +++++--- test/helper/Puppeteer_test.js | 33 ++++++++++++++++++++++--------- 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/docs/helpers/Puppeteer.md b/docs/helpers/Puppeteer.md index 9a8a232b1..ea49b630a 100644 --- a/docs/helpers/Puppeteer.md +++ b/docs/helpers/Puppeteer.md @@ -473,15 +473,17 @@ I.doubleClick('.btn.edit'); ### downloadFile Performs a download file on an element matched by link|button|CSS or XPath. -File is downloaded by default to output folder +File is downloaded by default to output folder. +If no custom file name is provided, the default name will be used ```js -I.downloadFile('td[class="text-right file-link"] a'); +I.downloadFile('td[class="text-right file-link"] a', 'thisIsCustomName'); ``` #### Parameters - `locator` clickable link or button located by CSS|XPath locator. +- `string` custom file name. ### dragAndDrop diff --git a/docs/webapi/downloadFile.mustache b/docs/webapi/downloadFile.mustache index 1744f5f9f..b5ea29ab1 100644 --- a/docs/webapi/downloadFile.mustache +++ b/docs/webapi/downloadFile.mustache @@ -1,9 +1,11 @@ Performs a download file on an element matched by link|button|CSS or XPath. -File is downloaded by default to output folder +File is downloaded by default to output folder. +If no custom file name is provided, the default name will be used ```js -I.downloadFile('td[class="text-right file-link"] a'); +I.downloadFile('td[class="text-right file-link"] a', 'thisIsCustomName'); ``` -@param locator clickable link or button located by CSS|XPath locator. \ No newline at end of file +@param locator clickable link or button located by CSS|XPath locator. +@param string custom file name. \ No newline at end of file diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index cef4e79ea..cd39d4722 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -856,14 +856,16 @@ class Puppeteer extends Helper { /** * {{> ../webapi/downloadFile }} */ - async downloadFile(locator) { + async downloadFile(locator, customName) { let fileName; await this.page.setRequestInterception(true); this.click(locator); const xRequest = await new Promise((resolve) => { this.page.on('request', (request) => { - fileName = request.url().split('/')[request.url().split('/').length - 1]; + const grabbedFileName = request.url().split('/')[request.url().split('/').length - 1]; + const fileExtension = request.url().split('/')[request.url().split('/').length - 1].split('.')[1]; + customName ? fileName = `${customName}.${fileExtension}` : fileName = grabbedFileName; request.abort(); resolve(request); }); @@ -891,7 +893,7 @@ class Puppeteer extends Helper { wstream.write(response.data); wstream.end(); this.debug(`File is downloaded in ${outputFile}`); - return outputFile; + return fileName; } catch (error) { throw new Error(`There is something wrong with downloaded file. ${error}`); } diff --git a/test/helper/Puppeteer_test.js b/test/helper/Puppeteer_test.js index 49b3b9b1a..2950652b7 100644 --- a/test/helper/Puppeteer_test.js +++ b/test/helper/Puppeteer_test.js @@ -10,10 +10,12 @@ const AssertionFailedError = require('../../lib/assert/error'); const formContents = require('../../lib/utils').test.submittedData(path.join(__dirname, '/../data/app/db')); const expectError = require('../../lib/utils').test.expectError; const webApiTests = require('./webapi'); +const FileSystem = require('../../lib/helper/FileSystem'); let I; let browser; let page; +let FS; const siteUrl = TestHelper.siteUrl(); describe('Puppeteer', function () { @@ -22,11 +24,15 @@ describe('Puppeteer', function () { before(() => { global.codecept_dir = path.join(__dirname, '/../data'); - // create directory /download; - fs.mkdir(path.join(`${__dirname}/download`), () => { + // create download folder; + fs.mkdir(path.join(`${__dirname}/../data/download`), () => { }); - global.output_dir = path.join(`${__dirname}/download`); + global.output_dir = path.join(`${__dirname}/../data/download`); + + FS = new FileSystem(); + FS._before(); + FS.amInPath('download'); I = new Puppeteer({ url: siteUrl, @@ -63,9 +69,11 @@ describe('Puppeteer', function () { if (err) throw err; for (const file of files) { - fs.unlink(path.join(global.output_dir, file), (err) => { - if (err) throw err; - }); + if (file.includes('.mp4')) { + fs.unlink(path.join(global.output_dir, file), (err) => { + if (err) throw err; + }); + } } }); }); @@ -578,12 +586,19 @@ describe('Puppeteer', function () { }); }); - describe.only('#downloadFile', () => { + describe('#downloadFile', () => { it('should dowload file', async () => { await I.amOnPage('http://file-examples.com/index.php/sample-video-files/sample-mp4-files/'); - const outputFile = await I.downloadFile('td[class="text-right file-link"] a'); + const fileName = await I.downloadFile('td[class="text-right file-link"] a'); + + FS.seeFile(fileName); + }); + + it('should dowload file with custom name', async () => { + await I.amOnPage('http://file-examples.com/index.php/sample-video-files/sample-mp4-files/'); + const fileName = await I.downloadFile('td[class="text-right file-link"] a', 'thisisacustomname'); - assert.equal(fs.existsSync(path.join(outputFile)), true); + FS.seeFile(fileName); }); }); }); From 235c964a594044bf81a4cea736c1e659387dfe46 Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Wed, 6 Mar 2019 12:42:03 +0100 Subject: [PATCH 3/8] fixed tests --- lib/helper/Puppeteer.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index cd39d4722..c150d7574 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -889,11 +889,14 @@ class Puppeteer extends Helper { const outputFile = path.join(`${global.output_dir}/${fileName}`); try { - const wstream = fs.createWriteStream(outputFile); - wstream.write(response.data); - wstream.end(); - this.debug(`File is downloaded in ${outputFile}`); - return fileName; + return new Promise((resolve, reject) => { + const wstream = fs.createWriteStream(outputFile); + wstream.write(response.data); + wstream.end(); + this.debug(`File is downloaded in ${outputFile}`); + wstream.on("finish", () => { resolve(fileName); }); + wstream.on("error", reject); + }); } catch (error) { throw new Error(`There is something wrong with downloaded file. ${error}`); } From 1df2ed59a0ebea7c2fe10652bdd65c90115a0f26 Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Wed, 6 Mar 2019 12:44:09 +0100 Subject: [PATCH 4/8] lint fixed --- lib/helper/Puppeteer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index c150d7574..46ed772ac 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -894,8 +894,8 @@ class Puppeteer extends Helper { wstream.write(response.data); wstream.end(); this.debug(`File is downloaded in ${outputFile}`); - wstream.on("finish", () => { resolve(fileName); }); - wstream.on("error", reject); + wstream.on('finish', () => { resolve(fileName); }); + wstream.on('error', reject); }); } catch (error) { throw new Error(`There is something wrong with downloaded file. ${error}`); From a1317ef2693c2010b548d4848642eb08c549d4a0 Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Mon, 11 Mar 2019 10:00:09 +0100 Subject: [PATCH 5/8] debug --- lib/helper/Puppeteer.js | 1 + test/helper/Puppeteer_test.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index 46ed772ac..dbd6016c6 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -891,6 +891,7 @@ class Puppeteer extends Helper { try { return new Promise((resolve, reject) => { const wstream = fs.createWriteStream(outputFile); + console.log(response.data); wstream.write(response.data); wstream.end(); this.debug(`File is downloaded in ${outputFile}`); diff --git a/test/helper/Puppeteer_test.js b/test/helper/Puppeteer_test.js index 2950652b7..28d1e2291 100644 --- a/test/helper/Puppeteer_test.js +++ b/test/helper/Puppeteer_test.js @@ -586,7 +586,7 @@ describe('Puppeteer', function () { }); }); - describe('#downloadFile', () => { + describe.only('#downloadFile', () => { it('should dowload file', async () => { await I.amOnPage('http://file-examples.com/index.php/sample-video-files/sample-mp4-files/'); const fileName = await I.downloadFile('td[class="text-right file-link"] a'); From 40f9bc11e8c4ee916ece4cfdcc03a344a6450c45 Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Mon, 11 Mar 2019 10:09:34 +0100 Subject: [PATCH 6/8] removed .only from describe --- test/helper/Puppeteer_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/helper/Puppeteer_test.js b/test/helper/Puppeteer_test.js index 28d1e2291..2950652b7 100644 --- a/test/helper/Puppeteer_test.js +++ b/test/helper/Puppeteer_test.js @@ -586,7 +586,7 @@ describe('Puppeteer', function () { }); }); - describe.only('#downloadFile', () => { + describe('#downloadFile', () => { it('should dowload file', async () => { await I.amOnPage('http://file-examples.com/index.php/sample-video-files/sample-mp4-files/'); const fileName = await I.downloadFile('td[class="text-right file-link"] a'); From 96af0c0bdc8170da2ca9b42022610b01b065d391 Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Mon, 11 Mar 2019 11:13:43 +0100 Subject: [PATCH 7/8] fixed failed test --- lib/helper/Puppeteer.js | 1 - test/helper/Puppeteer_test.js | 53 +++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/lib/helper/Puppeteer.js b/lib/helper/Puppeteer.js index dbd6016c6..46ed772ac 100644 --- a/lib/helper/Puppeteer.js +++ b/lib/helper/Puppeteer.js @@ -891,7 +891,6 @@ class Puppeteer extends Helper { try { return new Promise((resolve, reject) => { const wstream = fs.createWriteStream(outputFile); - console.log(response.data); wstream.write(response.data); wstream.end(); this.debug(`File is downloaded in ${outputFile}`); diff --git a/test/helper/Puppeteer_test.js b/test/helper/Puppeteer_test.js index 2950652b7..57aa52677 100644 --- a/test/helper/Puppeteer_test.js +++ b/test/helper/Puppeteer_test.js @@ -24,15 +24,6 @@ describe('Puppeteer', function () { before(() => { global.codecept_dir = path.join(__dirname, '/../data'); - // create download folder; - fs.mkdir(path.join(`${__dirname}/../data/download`), () => { - - }); - global.output_dir = path.join(`${__dirname}/../data/download`); - - FS = new FileSystem(); - FS._before(); - FS.amInPath('download'); I = new Puppeteer({ url: siteUrl, @@ -63,21 +54,6 @@ describe('Puppeteer', function () { return I._after(); }); - after(() => { - // Remove the test dir - fs.readdir(global.output_dir, (err, files) => { - if (err) throw err; - - for (const file of files) { - if (file.includes('.mp4')) { - fs.unlink(path.join(global.output_dir, file), (err) => { - if (err) throw err; - }); - } - } - }); - }); - describe('open page : #amOnPage', () => { it('should open main page of configured site', async () => { await I.amOnPage('/'); @@ -587,6 +563,35 @@ describe('Puppeteer', function () { }); describe('#downloadFile', () => { + before(() => { + // create download folder; + fs.mkdir(path.join(`${__dirname}/../data/download`), () => { + + }); + global.output_dir = path.join(`${__dirname}/../data/download`); + + FS = new FileSystem(); + FS._before(); + FS.amInPath('download'); + }); + + after(() => { + // Remove the test dir + fs.readdir(global.output_dir, (err, files) => { + if (err) throw err; + + for (const file of files) { + if (file.includes('.mp4')) { + fs.unlink(path.join(global.output_dir, file), (err) => { + if (err) throw err; + }); + } + } + }); + }); + + + it('should dowload file', async () => { await I.amOnPage('http://file-examples.com/index.php/sample-video-files/sample-mp4-files/'); const fileName = await I.downloadFile('td[class="text-right file-link"] a'); From de83d44171fce2e5f6bdbbb9a0ea4f87a05eeedb Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Mon, 11 Mar 2019 11:46:24 +0100 Subject: [PATCH 8/8] lint fixed --- test/helper/Puppeteer_test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/helper/Puppeteer_test.js b/test/helper/Puppeteer_test.js index 57aa52677..b2f648b08 100644 --- a/test/helper/Puppeteer_test.js +++ b/test/helper/Puppeteer_test.js @@ -591,7 +591,6 @@ describe('Puppeteer', function () { }); - it('should dowload file', async () => { await I.amOnPage('http://file-examples.com/index.php/sample-video-files/sample-mp4-files/'); const fileName = await I.downloadFile('td[class="text-right file-link"] a');