Skip to content

Commit

Permalink
fix: prepare jsHandle.uploadFile for CDP Page.handleFileChooser remov…
Browse files Browse the repository at this point in the history
…al (#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.
  • Loading branch information
mathiasbynens committed Dec 3, 2019
1 parent 8b49dc6 commit 6091a34
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 6 deletions.
37 changes: 31 additions & 6 deletions lib/JSHandle.js
Expand Up @@ -15,7 +15,6 @@
*/

const {helper, assert, debugError} = require('./helper');
const path = require('path');

function createJSHandle(context, remoteObject) {
const frame = context.frame();
Expand Down Expand Up @@ -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);
}
Expand All @@ -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() {
Expand Down
2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -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",
Expand Down

1 comment on commit 6091a34

@Georgegriff
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mathiasbynens
Since 2.1.0 I'm finding uploadFile with is handle isn't working for my e2e tests :( downgraded to 2.0.0 and all is fine #5420 wondering if this might be why? In linked issue is code snippet from CodeceptJS

Please sign in to comment.