Skip to content

Commit 3b8dbb1

Browse files
committed
Verify download file example
1 parent ea0abad commit 3b8dbb1

File tree

3 files changed

+939
-517
lines changed

3 files changed

+939
-517
lines changed

package.json

+12-12
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,25 @@
1111
"node": ">=8"
1212
},
1313
"dependencies": {
14-
"caniuse-db": "^1.0.30000884",
14+
"caniuse-db": "^1.0.30000921",
1515
"chalk": "^2.3.2",
16-
"chrome-har": "^0.3.1",
17-
"chrome-launcher": "^0.10.2",
16+
"chrome-har": "^0.7.1",
17+
"chrome-launcher": "^0.10.5",
1818
"cli-table": "^0.3.1",
1919
"del": "^3.0.0",
20-
"express": "^4.16.3",
21-
"lighthouse": "^3.0.3",
22-
"mime": "^2.3.1",
23-
"node-fetch": "^2.1.2",
20+
"express": "^4.16.4",
21+
"lighthouse": "^4.0.0-alpha.2-3.2.1",
22+
"mime": "^2.4.0",
23+
"node-fetch": "^2.3.0",
2424
"pixel-diff": "^1.0.1",
2525
"pngjs": "^3.3.3",
26-
"puppeteer": "^1.8.0",
27-
"request": "^2.85.0",
26+
"puppeteer": "^1.11.0",
27+
"request": "^2.88.0",
2828
"request-promise": "^4.2.2",
2929
"request-promise-native": "^1.0.5",
3030
"resize-img": "^1.1.2",
31-
"sharp": "^0.20.1",
32-
"ws": "^5.1.1",
33-
"yargs": "^11.0.0"
31+
"sharp": "^0.21.1",
32+
"ws": "^6.1.2",
33+
"yargs": "^12.0.5"
3434
}
3535
}

verify_download.js

+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/**
2+
* Copyright 2018 Google Inc. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* @author ebidel@ (Eric Bidelman)
17+
*/
18+
19+
/**
20+
* Shows how to click a file download link and verify that that file gets
21+
* downloaded to the local filesystem in the expected location.
22+
* Note: this approach only works in headful Chrome.
23+
*
24+
* Install:
25+
* npm i puppeteer
26+
* Run:
27+
* node verify_download.js
28+
*/
29+
30+
const puppeteer = require('puppeteer');
31+
const fs = require('fs');
32+
const path = require('path');
33+
const os = require('os');
34+
35+
const DOWNLOADS_FOLDER = `${os.homedir()}/Downloads`;
36+
37+
/**
38+
* From @xprudhomme.
39+
* Check if file exists, watching containing directory meanwhile.
40+
* Resolve if the file exists, or if the file is created before the timeout
41+
* occurs.
42+
* @param {string} filePath
43+
* @param {integer} timeout
44+
*/
45+
function checkFileExists(filePath, timeout=15000) {
46+
return new Promise((resolve, reject) => {
47+
const dir = path.dirname(filePath);
48+
const basename = path.basename(filePath);
49+
50+
const watcher = fs.watch(dir, (eventType, filename) => {
51+
if (eventType === 'rename' && filename === basename) {
52+
clearTimeout(timer);
53+
watcher.close();
54+
resolve(basename);
55+
}
56+
});
57+
58+
const timer = setTimeout(() => {
59+
watcher.close();
60+
reject(new Error(' [checkFileExists] File does not exist, and was not created during the timeout delay.'));
61+
}, timeout);
62+
63+
fs.access(filePath, fs.constants.R_OK, err => {
64+
if (!err) {
65+
clearTimeout(timer);
66+
watcher.close();
67+
resolve(basename);
68+
}
69+
});
70+
});
71+
}
72+
73+
/**
74+
* @param {!Browser} browser
75+
* @param {string} url The URL of the download file to wait for.
76+
* @returns {!Promise<!Object>} Metadata about the latest file in Download Manager.
77+
*/
78+
async function waitForFileToDownload(browser, url) {
79+
const downloadPage = await browser.newPage();
80+
// Note: navigating to this page only works in headful chrome.
81+
await downloadPage.goto('chrome://downloads/');
82+
83+
// Wait for our download to show up in the list by matching on its url.
84+
const jsHandle = await downloadPage.waitForFunction(downloadUrl => {
85+
const manager = document.querySelector('downloads-manager');
86+
const downloads = manager.items_.length;
87+
const lastDownload = manager.items_[0];
88+
if (downloads && lastDownload.url === downloadUrl &&
89+
lastDownload.state === 'COMPLETE') {
90+
return manager.items_[0];
91+
}
92+
}, {polling: 100}, url);
93+
94+
const fileMeta = await jsHandle.jsonValue();
95+
96+
await downloadPage.close();
97+
98+
return fileMeta;
99+
}
100+
101+
/**
102+
* @param {!Browser} browser
103+
* @param {string} url The url of the page to navigate to.
104+
* @param {string} text The link with this text to find and click on the page.
105+
* @returns {!Promise<?string>} The download resource's url.
106+
*/
107+
async function clickDownloadLink(browser, url, text) {
108+
const page = await browser.newPage();
109+
await page.goto(url, {waitUntil: 'networkidle2'});
110+
111+
const downloadUrl = await page.evaluate((text) => {
112+
const link = document.evaluate(`//a[text()="${text}"]`, document,
113+
null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
114+
if (link) {
115+
link.click();
116+
return link.href;
117+
}
118+
return null;
119+
}, text);
120+
121+
await page.close();
122+
123+
return downloadUrl;
124+
}
125+
126+
(async() => {
127+
128+
const browser = await puppeteer.launch({
129+
headless: false,
130+
// dumpio: true,
131+
});
132+
133+
// TODO: setDownloadBehavior would be a good approach, as we could check
134+
// that the file shows up in the location specified by downloadPath. Howeverm
135+
// that arg doesn't currently work.
136+
// const client = await page.target().createCDPSession();
137+
// await client.send('Page.setDownloadBehavior', {
138+
// behavior: 'allow',
139+
// downloadPath: path.resolve(__dirname, 'downloads'),
140+
// });
141+
142+
// await client.detach();
143+
144+
// 1. navigate to a page with a bunch links to download.
145+
// 2. click the "Short Selling (csv)" link on the page. The browser force downloads the file.
146+
const url = 'https://www.nseindia.com/products/content/equities/equities/homepage_eq.htm';
147+
const downloadUrl = await clickDownloadLink(browser, url, 'Short Selling (csv)');
148+
149+
if (!downloadUrl) {
150+
console.error('Did not find download link!');
151+
return;
152+
}
153+
154+
// 3. Open chrome:downloads and wait for the file to be downloaded.
155+
const fileMeta = await waitForFileToDownload(browser, downloadUrl);
156+
157+
console.log(`"${fileMeta.file_name}" was downloaded`);
158+
159+
// 4. Optionally check that the file really ends up in the expected location
160+
// on the filesystem.
161+
const exists = await checkFileExists(`${DOWNLOADS_FOLDER}/${fileMeta.file_name}`);
162+
console.assert(exists, `${fileMeta.file_name} was not downloaded to correct location.`);
163+
164+
await browser.close();
165+
166+
})();

0 commit comments

Comments
 (0)