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

Handling File Input Dialogs #2946

Closed
KJ1i opened this issue Jul 24, 2018 · 45 comments · Fixed by #4653
Closed

Handling File Input Dialogs #2946

KJ1i opened this issue Jul 24, 2018 · 45 comments · Fixed by #4653
Labels
chromium Issues with Puppeteer-Chromium feature upstream

Comments

@KJ1i
Copy link

KJ1i commented Jul 24, 2018

Is there any way to handle File Input Dialogs?

When I click an element on the page, it opens up the upload file dialog.

I can not use elementHandle.uploadFile as it is not an input[type="file"]. Plus, #1376 will not help as, dragging and dropping in the file upload field does not work, instead, dragging and dropping opens up the file in the browser tab.

I am using Windows, so there won't be the problem where, file dialog behavior is different across operating systems.

So, can you provide some example code on how would I go about doing that? Thanks!

@KJ1i
Copy link
Author

KJ1i commented Jul 24, 2018

If there is something like which could keyboard.type into the file dialog and press enter, that would do the trick. We can accomplish this using different node packages that generate keyboard events at operating system level, but, that requires the browser to always be in focus.

So, is there something like this possible in Puppeteer?

@aslushnikov
Copy link
Contributor

So, is there something like this possible in Puppeteer?

@KJ1i Puppeteer generally operates on the web page level; we don't support the fileinput dialog and instead "override" it with elementHandle.uploadFile.

How's the file input dialog opened? Maybe I'll be able to come up with a workaround for your case.

@KJ1i
Copy link
Author

KJ1i commented Jul 26, 2018

@aslushnikov Thanks for replying!

Here is the image of the website upload button:-

upload

When we click on Browse button, it opens up the file dialog and, then, after selecting the file in the file dialog, it fills the <input type="text"> which is at the left side of the button.

The following is the website:- http://www.createspace.com
If you want, I can create an account for you here and message you its login details.

I have asked this question on StackOverflow also:- https://stackoverflow.com/questions/51491928/uploading-a-file-on-non-input-type-file
It contains more info about the question in hand.

Please let me know if more details are needed.
Thanks a lot for replying!

Awaiting your reply.

@cloudZQY
Copy link

I have a similar problem.

I use a custom plugin ng-file-upload in my project, when I click a element like button and trigger a event, this plugin will create a <input type="file"> and click it. so I can't get <input type="file"> in my page. The elementHandle.uploadFile also has no help for me.

I think this is a very common practice to upload file, but I can't use puppeteer to resolve it. Please give some help for me.

@HawkiesZA
Copy link

Also having the same problem as @KJ1i where clicking on an element opens a native dialog (and it's not input[type="file"]).

@aslushnikov
Copy link
Contributor

@KJ1i @cloudZQY @HawkiesZA this is indeed poorly supported atm; I failed to come up with any reasonable workaround for you guys.

For this to work properly, we need to expose more events from DevTools procol, similarly how we did it with javascript dialogs.

Please upvote the issue to bump its priority. We rely on "likes" to figure what's most important to do next.

@chrisngr
Copy link

sounds like a must have feature, most sites these days tend to use alternative file upload controls instead of the common file input

@uprisinginv
Copy link

I would really like to see this feature supported soon !

@parasvora
Copy link

This support is something which I am in need too, any plan to provide a fix on this?

@nuc
Copy link

nuc commented Nov 13, 2018

Seems that for my specific case, I was able to work it out:

  • Click on the button which triggers the native file input dialog.
  • Look for input[type="file"] and upload your file over there.

Here's a naive example:

  await page.waitForSelector('.file-dialog-trigger')
  await page.click('.file-dialog-trigger')
  const input = await page.$('input[type="file"]')
  await input.uploadFile('./content.csv')

@li-01
Copy link

li-01 commented Dec 5, 2018

need this feature badly!

@aslushnikov aslushnikov added the chromium Issues with Puppeteer-Chromium label Dec 6, 2018
@Keerthivasanmohan
Copy link

Keerthivasanmohan commented Jan 7, 2019

Hi Team,
The above solution works partially, the file is uploaded but the content of the file is not update any input on this please help me, following was the image
image
image

my selector:
var findelement = await bs.page.$("#upload-used-car-photo > span > div.ant-upload.ant-upload-drag > span >input[type='file']");
await findelement.uploadFile(absoultepath);

@bexoss
Copy link

bexoss commented Feb 28, 2019

@nuc

I also work it out using your way.
But problem is the file dialog is still opened even after upload file succeed.
How can you close file dialog?

@bdrtsky
Copy link

bdrtsky commented Mar 3, 2019

Looking forward for this feature. Also have this issue!

@remote-specialist
Copy link

Any progress on this?

@adrianhelvik
Copy link

I second the need for this. I am writing a fuzz tester for our app. Works great, but I'd love to be able to upload a generic image whenever a file dialog appears.

This would be a sweet API:

page.on('filedialog', async input => {
  await input.uploadFile('./foo.jpg')
})

@Kalliser
Copy link

Kalliser commented May 9, 2019

I confirm this is much needed

@Omurshid
Copy link

Omurshid commented Jun 5, 2019

Is there any progress on this? me and my team would love for this feature to be implemented.

@chrisJohn404
Copy link

Agreed, this would be nice for testing server google cloud server deployments of Drupal, Wordpress, and others just to make sure files can be uploaded properly.

@erm500
Copy link

erm500 commented Jun 9, 2019

await this.core.bot.emulate(iPhone);
let selector = "#react-root section nav div div header div.b5itu div button";
await this.core.bot.waitForSelector(selector, {timeout: 5000});
let button = await this.core.bot.$(selector);
await button.click();
let select = "input[type=\"file\"]"; //input.tb_sK
await this.core.bot.waitForSelector(select, {timeout: 5000});
let input = await this.core.bot.$(select);
let filePath = path.relative(process.cwd(), __dirname + '/assets/ByaFCAwApsN.jpg');
await input.uploadFile(filePath);

Actions are performed, but the file is not loaded. Why not working?

@slmgc
Copy link

slmgc commented Jun 10, 2019

@Ermolaev-Nikolay try using another selector for select variable, e.g.: #react-root input[type=\"file\"]". I saw an issue before when it didn't work with the input[type=file] selector even though it was a valid one.

@erm500
Copy link

erm500 commented Jun 10, 2019

@slmgc, thank you for the answer, but seems the problem in another. It seems the photo is loaded, but instead of the edit window goes to main page.

@marcelinhov2
Copy link

Anybody solve it? Thanks

aslushnikov added a commit to aslushnikov/puppeteer that referenced this issue Jun 29, 2019
This roll includes:
- https://crrev.com/673121 - DevTools: intercept file chooser requests

References puppeteer#2946
@aispark
Copy link

aispark commented Dec 1, 2019

@sekreiner I have the same problem.
Is it solved?

@Versiani-R
Copy link

I'm having the same issue. I cannot send an image to a facebook input [type=file]. Did anyone figured it out ?

@robinjoerke
Copy link

robinjoerke commented Mar 2, 2020

if you you youse some kind of upload library (react-dropzone in my case) you can try to trigger a change event on the input after uploading the file.

await page.waitForSelector('input[type=file]');
const fileInput = await page.$(''input[type=file]');
await fileInput.uploadFile("./testfile.pdf");
await fileInput.evaluate(upload => upload.dispatchEvent(new Event('change', { bubbles: true })));

this did the trick for me

@windmemory
Copy link

@robinjoerke 's solution works like a charm for me. Thanks for sharing!

@sergtimosh
Copy link

@robinjoerke , thanks! At last somebody found a solution that is working.
@aslushnikov maybe that should be fixed on puppeteer/playwrite API level? Because it's the same on both of libraries - it does attach file to element, but upload event isn't triggered. Same cases are working with the help of webdriver with no issues.

@mrdibre
Copy link

mrdibre commented Mar 20, 2020

if you you youse some kind of upload library (react-dropzone in my case) you can try to trigger a change event on the input after uploading the file.

await page.waitForSelector('input[type=file]');
const fileInput = await page.$(''input[type=file]');
await fileInput.uploadFile("./testfile.pdf");
await fileInput.evaluate(upload => upload.dispatchEvent(new Event('change', { bubbles: true })));

this did the trick for me

Thanks, it works.

@cl690924393
Copy link

if you you youse some kind of upload library (react-dropzone in my case) you can try to trigger a change event on the input after uploading the file.

await page.waitForSelector('input[type=file]');
const fileInput = await page.$(''input[type=file]');
await fileInput.uploadFile("./testfile.pdf");
await fileInput.evaluate(upload => upload.dispatchEvent(new Event('change', { bubbles: true })));

this did the trick for me

if you you youse some kind of upload library (react-dropzone in my case) you can try to trigger a change event on the input after uploading the file.

await page.waitForSelector('input[type=file]');
const fileInput = await page.$(''input[type=file]');
await fileInput.uploadFile("./testfile.pdf");
await fileInput.evaluate(upload => upload.dispatchEvent(new Event('change', { bubbles: true })));

this did the trick for me

This code works very well thanks, but I have a problem, event object received by my event listener doesn't have a file type when I trigger a change event. Like this event.target.files[0].type = "". Normally, event.target.files[0].type should have a value like event.target.files[0].type = "image/png".
What should i do.

@windware-ono
Copy link

@robinjoerke's code looks a bit hackish but has anyone actually managed to use the fileChooser API (waitForFileChooser and accept) or is it broken?

@robinjoerke
Copy link

robinjoerke commented Apr 3, 2020

This code works very well thanks, but I have a problem, event object received by my event listener doesn't have a file type when I trigger a change event. Like this event.target.files[0].type = "". Normally, event.target.files[0].type should have a value like event.target.files[0].type = "image/png".
What should i do.

As I said I was using an upload library, I was not noticing this issue (library somehow just ignored this). But backend always recieved contentType "application/octet-stream". Should have been something as "image/png" as well. This might be an effect of the issue you have. What I do to fix this is just guess the content type from the file extension part of the filename. Not a nice solution but works for my testing scenarios.

@windware-ono
Copy link

I think the biggest problem is that the file will be sent as application/octet-stream which would break the upload on the server side that wants to treat the upload depending on the content-type (I know it shouldn't rely on it, but I'm not at a liberty to modify the receiving end's server side code) being sent from the browser which is a very different behavior from a natural browser.

I have searched around a lot but I cannot figure out how to set content-type for the multipart header. Even tried to upload via XHR after setting the file with uploadFile but no luck and applying input.files[0].type = 'image/jpeg' won't change the content-type.

@yangmeili50
Copy link

if you you youse some kind of upload library (react-dropzone in my case) you can try to trigger a change event on the input after uploading the file.

await page.waitForSelector('input[type=file]');
const fileInput = await page.$(''input[type=file]');
await fileInput.uploadFile("./testfile.pdf");
await fileInput.evaluate(upload => upload.dispatchEvent(new Event('change', { bubbles: true })));

this did the trick for me

Thanks a lot!!! It works for me.

@haz3haz3
Copy link

    await page.waitForSelector('input[type=file]');
    await page.waitFor(1000);
    const input = await page.$('input[type="file"]');
    await input.uploadFile(filepath);

this works without click on the button and without a remaining open windows from the browser

@solartes
Copy link

solartes commented Jun 9, 2020

Seems that for my specific case, I was able to work it out:

  • Click on the button which triggers the native file input dialog.
  • Look for input[type="file"] and upload your file over there.

Here's a naive example:

  await page.waitForSelector('.file-dialog-trigger')
  await page.click('.file-dialog-trigger')
  const input = await page.$('input[type="file"]')
  await input.uploadFile('./content.csv')

You saved my life man!!!!

@yuzararyadi
Copy link

This works for me:

const [fileChooser] = await Promise.all([ page.waitForFileChooser(), page.click('.file-dialog-triger'), ]); await fileChooser.accept([./content.csv']);

@ralyodio
Copy link

How do you close the dialog?

@yuzararyadi
Copy link

How do you close the dialog?

using that code, the dialog there is no pop up dialog appear. it automatically upload the file without open file dialog

@Richienb
Copy link

Richienb commented Aug 14, 2020

Simplest example:

const fileInput = await page.$('#file-input')
await fileInput.uploadFile(filename)

If a button spawns the input dialog:

const [fileInput] = await Promise.all([page.waitForFileChooser(), page.click("#file-input")])
await fileInput.accept([filename])

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
chromium Issues with Puppeteer-Chromium feature upstream
Projects
None yet
Development

Successfully merging a pull request may close this issue.