fix(JSHandle): Fixes file upload (#5655)
This PR returns to using `DOM.setFileInputFiles`, but with some additional fixes and checks for events and multiple files.
This commit is contained in:
parent
3e4c8c9d0d
commit
532ae573d2
@ -313,36 +313,29 @@ class ElementHandle extends JSHandle {
|
|||||||
async uploadFile(...filePaths) {
|
async uploadFile(...filePaths) {
|
||||||
const isMultiple = await this.evaluate(element => element.multiple);
|
const isMultiple = await this.evaluate(element => element.multiple);
|
||||||
assert(filePaths.length <= 1 || isMultiple, 'Multiple file uploads only work with <input type=file multiple>');
|
assert(filePaths.length <= 1 || isMultiple, 'Multiple file uploads only work with <input type=file multiple>');
|
||||||
// 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));
|
// This import is only needed for `uploadFile`, so keep it scoped here to avoid paying
|
||||||
const files = [];
|
// the cost unnecessarily.
|
||||||
for (let i = 0; i < filePaths.length; i++) {
|
const path = require('path');
|
||||||
const buffer = await promises[i];
|
const files = filePaths.map(filePath => path.resolve(filePath));
|
||||||
const filePath = path.basename(filePaths[i]);
|
const { objectId } = this._remoteObject;
|
||||||
const file = {
|
const { node } = await this._client.send('DOM.describeNode', { objectId });
|
||||||
name: filePath,
|
const { backendNodeId } = node;
|
||||||
content: buffer.toString('base64'),
|
|
||||||
mimeType: mime.lookup(filePath),
|
// The zero-length array is a special case, it seems that DOM.setFileInputFiles does
|
||||||
};
|
// not actually update the files in that case, so the solution is to eval the element
|
||||||
files.push(file);
|
// value to a new FileList directly.
|
||||||
|
if (files.length === 0) {
|
||||||
|
await this.evaluate(element => {
|
||||||
|
element.files = new DataTransfer().files;
|
||||||
|
|
||||||
|
// Dispatch events for this case because it should behave akin to a user action.
|
||||||
|
element.dispatchEvent(new Event('input', { bubbles: true }));
|
||||||
|
element.dispatchEvent(new Event('change', { bubbles: true }));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await this._client.send('DOM.setFileInputFiles', { objectId, files, backendNodeId });
|
||||||
}
|
}
|
||||||
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 }));
|
|
||||||
element.dispatchEvent(new Event('change', { bubbles: true }));
|
|
||||||
}, files);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async tap() {
|
async tap() {
|
||||||
|
@ -38,6 +38,7 @@ describe('input tests', function() {
|
|||||||
}, input);
|
}, input);
|
||||||
await input.uploadFile(filePath);
|
await input.uploadFile(filePath);
|
||||||
expect(await page.evaluate(e => e.files[0].name, input)).toBe('file-to-upload.txt');
|
expect(await page.evaluate(e => e.files[0].name, input)).toBe('file-to-upload.txt');
|
||||||
|
expect(await page.evaluate(e => e.files[0].type, input)).toBe('text/plain');
|
||||||
expect(await page.evaluate(() => window._inputEvents)).toEqual(['input', 'change']);
|
expect(await page.evaluate(() => window._inputEvents)).toEqual(['input', 'change']);
|
||||||
expect(await page.evaluate(e => {
|
expect(await page.evaluate(e => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
|
Loading…
Reference in New Issue
Block a user