fix: prepare jsHandle.uploadFile for CDP Page.handleFileChooser removal (#5196)

* fix: prepare jsHandle.uploadFile for CDP Page.handleFileChooser removal

https://chromium-review.googlesource.com/c/chromium/src/+/1935410
removes Page.handleFileChooser from the CDP.

* fix: improve binary file support

UTF-8-decoding the input file could fail for binary files, and so we
now read the raw file buffer and base64-encode it. To base64-decode it
within the page context, we use the Fetch API in combination with a
data URL. This requires knowing the proper MIME type for the input
file, which we now figure out using the new mime-types dependency.
This commit is contained in:
Mathias Bynens 2019-12-03 09:18:18 +01:00 committed by GitHub
parent 8b49dc62a6
commit 6091a34a36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 6 deletions

View File

@ -15,7 +15,6 @@
*/
const {helper, assert, debugError} = require('./helper');
const path = require('path');
function createJSHandle(context, remoteObject) {
const frame = context.frame();
@ -302,8 +301,8 @@ class ElementHandle extends JSHandle {
if (option.selected && !element.multiple)
break;
}
element.dispatchEvent(new Event('input', { 'bubbles': true }));
element.dispatchEvent(new Event('change', { 'bubbles': true }));
element.dispatchEvent(new Event('input', { bubbles: true }));
element.dispatchEvent(new Event('change', { bubbles: true }));
return options.filter(option => option.selected).map(option => option.value);
}, values);
}
@ -312,9 +311,35 @@ class ElementHandle extends JSHandle {
* @param {!Array<string>} filePaths
*/
async uploadFile(...filePaths) {
const files = filePaths.map(filePath => path.resolve(filePath));
const objectId = this._remoteObject.objectId;
await this._client.send('DOM.setFileInputFiles', { objectId, files });
// These imports are only needed for `uploadFile`, so keep them
// scoped here to avoid paying the cost unnecessarily.
const path = require('path');
const mime = require('mime-types');
const fs = require('fs');
const readFileAsync = helper.promisify(fs.readFile);
const promises = filePaths.map(filePath => readFileAsync(filePath));
const files = [];
for (let i = 0; i < filePaths.length; i++) {
const buffer = await promises[i];
const filePath = path.basename(filePaths[i]);
const file = {
name: filePath,
content: buffer.toString('base64'),
mimeType: mime.lookup(filePath),
};
files.push(file);
}
await this.evaluateHandle(async(element, files) => {
const dt = new DataTransfer();
for (const item of files) {
const response = await fetch(`data:${item.mimeType};base64,${item.content}`);
const file = new File([await response.blob()], item.name);
dt.items.add(file);
}
element.files = dt.files;
element.dispatchEvent(new Event('input', { bubbles: true }));
}, files);
}
async tap() {

View File

@ -30,10 +30,12 @@
"author": "The Chromium Authors",
"license": "Apache-2.0",
"dependencies": {
"@types/mime-types": "^2.1.0",
"debug": "^4.1.0",
"extract-zip": "^1.6.6",
"https-proxy-agent": "^3.0.0",
"mime": "^2.0.3",
"mime-types": "^2.1.25",
"progress": "^2.0.1",
"proxy-from-env": "^1.0.0",
"rimraf": "^2.6.1",