fix(setInputFiles): make it work with CSP enabled (#3756)

We used to do fetch() to decode the file buffer. However, this is
blocked by strict CSP policy. Instead, we can use explicit
string -> bytes conversion, and trade performance for CSP compliance.
This commit is contained in:
Dmitry Gozman 2020-09-03 10:09:03 -07:00 committed by GitHub
parent f232f34dae
commit c190310335
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 14 additions and 5 deletions

View file

@ -452,7 +452,7 @@ export class InjectedScript {
throw new Error('Not a checkbox');
}
async setInputFiles(node: Node, payloads: { name: string, mimeType: string, buffer: string }[]) {
setInputFiles(node: Node, payloads: { name: string, mimeType: string, buffer: string }[]) {
if (node.nodeType !== Node.ELEMENT_NODE)
return 'Node is not of type HTMLElement';
const element: Element | undefined = node as Element;
@ -463,10 +463,10 @@ export class InjectedScript {
if (type !== 'file')
return 'Not an input[type=file] element';
const files = await Promise.all(payloads.map(async file => {
const result = await fetch(`data:${file.mimeType};base64,${file.buffer}`);
return new File([await result.blob()], file.name, {type: file.mimeType});
}));
const files = payloads.map(file => {
const bytes = Uint8Array.from(atob(file.buffer), c => c.charCodeAt(0));
return new File([bytes], file.name, { type: file.mimeType });
});
const dt = new DataTransfer();
for (const file of files)
dt.items.add(file);

View file

@ -115,6 +115,15 @@ it('should work when file input is not attached to DOM', async ({page, server})
expect(chooser).toBeTruthy();
});
it('should work with CSP', async ({page, server}) => {
server.setCSP('/empty.html', 'default-src "none"');
await page.goto(server.EMPTY_PAGE);
await page.setContent(`<input type=file>`);
await page.setInputFiles('input', path.join(__dirname, '/assets/file-to-upload.txt'));
expect(await page.$eval('input', input => input.files.length)).toBe(1);
expect(await page.$eval('input', input => input.files[0].name)).toBe('file-to-upload.txt');
});
it('should respect timeout', async ({page, playwright}) => {
let error = null;
await page.waitForEvent('filechooser', {timeout: 1}).catch(e => error = e);