Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

uploadFile doesn't work with puppeteer.connect #4405

Closed
sbekrin opened this issue May 8, 2019 · 14 comments
Closed

uploadFile doesn't work with puppeteer.connect #4405

sbekrin opened this issue May 8, 2019 · 14 comments

Comments

@sbekrin
Copy link
Contributor

sbekrin commented May 8, 2019

Steps to reproduce

Currently when used inputElement.uploadFile via puppeteer.connect, it uploads an empty file, as it doesn't exist on host machine. I believe this is a DevTools limitation and there's no possible workaround except uploading the file to remote puppeteer's host.

What steps will reproduce the problem?

  1. const page = await puppeteer.connect(/* ... */);
  2. const input = await page.$('input[type="file"]');
  3. await input.uploadFile('./this/will/upload/an/empty/file');

What is the expected result?

  • uploaded files are serialised before sent to devtools instead of their file paths,
  • or an error thrown saying this is not supported via connect.

What happens instead?

Puppeteer silently uploads an empty payload.

@paullewis
Copy link
Contributor

This should be fixed as of 532ae57 as we changed the underlying implementation to use DOM.setFileInputFiles, which behaves a lot more as expected. We also fire events for change and input, too. Going to close this issue, but please let us know if it's not fixed.

@sbekrin
Copy link
Contributor Author

sbekrin commented Apr 17, 2020

awesome, thanks for the update @paullewis!

@bloeys
Copy link

bloeys commented Apr 22, 2020

Hello

So using 3.0.1, we are still experiencing the exact same issue here, where we upload a file across the network (browser on a different machine). myElement.files gets populated with filename, date etc but the size is 0 and no file content.

Any help on getting this to work?

@mathiasbynens
Copy link
Member

@bloeys Take a look at the code that #5655 removes. You could do the same thing in your script: read and serialize the file in Node.js, then evaluate JavaScript in the page to dynamically set input.files = dt.files;.

@bloeys
Copy link

bloeys commented Apr 23, 2020

Thanks a lot for the tip @mathiasbynens, it was really helpful!

For anyone facing issues uploading with puppeteer, here is the code I went with that finally worked

const fileToUpload = {
  name: 'myFileName',
  content: fs.readFileSync('/file/path').toString(),
  mimeType: 'text/plain', // This will depend on your case
}

await page.evaluate(async (fileToUpload) => {

  //Create blob and file from file string
  const b = new Blob([fileToUpload.content], { type: fileToUpload.mimeType })
  const dt = new DataTransfer();
  dt.items.add(new File([b], fileToUpload.name));

  //Simulate drag and drop on your input field using DataTransfer class
  ele = document.querySelector('input[type=file]')
  ele.files = dt.files;
  ele.dispatchEvent(new Event('input', { bubbles: true }));
  ele.dispatchEvent(new Event('change', { bubbles: true }));
}, fileToUpload);

I hope this helps someone, instead of spending days working with and around puppeteer file upload.

However, @mathiasbynens do you have an idea of why the builtin calls (I see there is a CDP call in newer versions) in puppeteer don't work? It would be nice to understand why that happened.

Thanks again for your help.

@joelgriffith
Copy link
Contributor

joelgriffith commented Jul 25, 2020

Since puppeteer verifies that files are present on its local file-system, then this breaks connected sessions in an unintuitive way. Versions <= 3.0.0 handled this pretty well, but at the cost of sending more data over the network.

Is it possible to make it more graceful? For instance, if it's aconnected session then do the DataTransfer method, otherwise puppeteer can just pass the list of files over to chromium? Happy to do a PR, just don't want to waste the time if it's not viable.

@astanet
Copy link

astanet commented Oct 18, 2020

I'm facing similar issue. I'm developing an app using puppeteer with VSCode Remote-Containers and Remote-WSL feature. When developing on local environment, I want to watch how puppeteer controls Chrome, so I connect puppeteer from inside of container to Chrome on host using --remote-debugging-port option.
I succeeded download a file by specifying WSL path like \\wsl$\Ubuntu-18.04\home\foo\project. But I cannot upload a file with puppeteer.connect.

Of course upload feature works fine if completed inside the container in headless mode. But, if puppeteer can upload using remote Chrome, it will be really useful for debug in my situation.

@YusukeIwaki
Copy link
Contributor

This issue still occurs, and is inconvenient on working with browserless.io...

Is it possible to make it more graceful? For instance, if it's aconnected session then do the DataTransfer method, otherwise puppeteer can just pass the list of files over to chromium?

I think this solution is good,
and also I have another idea: creating a new method like ElementHandle.uploadFileWithStream(fileStream) and FileChooser.acceptWithStream(fileStream) which just have a logic like #4405 (comment).
By specifying stream, most users can imagine that the data (not file path) will be transfered to the remote browser.

const browser = await puppeteer.connect({ browserWSEndpoint: 'ws://.....' });
const page = await browser.newPage();

const input = await page.$('input[type="file"]')
await input.uploadFileWithStream(fs.createReadStream('./this/will/upload/an/empty/file'))

@jschfflr Hi, how you you think about the solution...?

@jschfflr
Copy link
Contributor

I would agree that we should somehow support uploading files on connected sessions too. Not sure though why the initial implementation got changed. Was that for performance reasons or for security reasons @mathiasbynens @paullewis?

If we added a streaming version (which I like) I would expect to actually stream the files content though. While that's certainly possible, it would be a bit more involved though. I'd be happy to accept a PR for that as soons as I understand the rational behind the original change.

@jschfflr jschfflr self-assigned this Sep 15, 2021
@YusukeIwaki
Copy link
Contributor

@jschfflr I also tried to know the reason. This is just my note but I share it.

#5655 seems to be a revert of #5196.


Puppeteer 2.0 used DOM.setInputFilesInput CDP command.
https://github.com/puppeteer/puppeteer/blob/v2.0.0/lib/JSHandle.js#L317

Then #5196 is introduced in Puppeteer 2.1.

However it brought some bugs.

A quick fix #5369 is merged into Puppeteer 2.1.1

However Puppeteer 2.1.1 still don't have change event dispatcher
https://github.com/puppeteer/puppeteer/blob/v2.1.1/lib/JSHandle.js#L343

Then all changes are reverted... (in Puppeteer 3.0 #5655)
#5420 (comment)


Initial Playwright implementation had the same code (without DOM.setFileInputFiles CDP command),
and a bugfix (dispatching change event) is merged in Playwright 0.12
microsoft/playwright@f2b2d72

Playwright still use the logic without DOM.setFileInputFiles
https://github.com/microsoft/playwright/blob/v1.14.1/src/server/injected/injectedScript.ts#L615

YusukeIwaki added a commit to YusukeIwaki/puppeteer that referenced this issue Sep 16, 2021
@jschfflr
Copy link
Contributor

Let's see if @mathiasbynens or @paullewis can fill in the blanks a bit here.

@jrandolf
Copy link
Contributor

jrandolf commented Jun 9, 2022

Oh, this is quite old. This is fixed in #8472.

@jrandolf jrandolf closed this as completed Jun 9, 2022
@bloeys
Copy link

bloeys commented Jun 9, 2022

Oh, this is quite old. This is fixed in #4405.

Sorry to reopen @jrandolf, but did you mean to link a different issue/PR?
Because you just linked back to this same issue.

@jrandolf
Copy link
Contributor

jrandolf commented Jun 9, 2022

Fixed! #8472

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants