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

Adding Ability to Submit File to Input Element From Local Filesystem (file upload) #170

Closed
pihish opened this issue Jun 15, 2016 · 185 comments · Fixed by #19524
Closed

Adding Ability to Submit File to Input Element From Local Filesystem (file upload) #170

pihish opened this issue Jun 15, 2016 · 185 comments · Fixed by #19524
Assignees
Labels

Comments

@pihish
Copy link

pihish commented Jun 15, 2016

Description
Our app takes a file from an user, does some work with it, and produces outputs based on the input the user provides. A bunch of things happen in the system during the processing and we expect project pages to be generated in a certain fashion after a project successfully completes. We need to be able to submit files through our webpage to test the affects of this process.

@jennifer-shehane jennifer-shehane added the type: feature New feature that does not currently exist label Jun 15, 2016
@brian-mann
Copy link
Member

This requires sending native events.

We've been holding off on adding native event support because of the way the debugger protocol works in Chrome. It can only accept one connection which means dev tools cannot be open. Forcing users to close their dev tools is a big reason why the testing ecosystem is so awful.

We've been investigating the user experience around this and we have some pretty good ideas about how to improve this. Once we add native events you'll be able to not just upload files but send native keyboard events, mobile events, and a slew of other things.

@brian-mann
Copy link
Member

Should also note that it is possible to upload files in your application but its different based on how you've written your own upload code.

For instance if you use the new fileReader API's you could use cy.readFile or cy.fixture to read in data, and then convert it to a Blob and then trigger the specific event your application is looking for and send in the Blob as a property.

Because the implementation is different per application there is no way for us to suggest how to do it. Once we implement native API's we will be able to show a recipe handling this.

@wescarr
Copy link

wescarr commented Jun 26, 2017

Wanted to add that I got this working by doing the following:

cy.fixture('path/to/image.png').as('logo')
  .get('input[type=file]').then(function(el) {
    return Cypress.Blob.base64StringToBlob(this.logo, 'image/png')
      .then(blob => {
        el[0].files[0] = blob
        el[0].dispatchEvent(new Event('change', {bubbles: true}))
      })
  })

@medeeiros
Copy link

I've tried everything and I can't get dropzone on my react app to recognise the file.

cy.get('input[type=file]', { force: true }).then(function(el) {
    const xml = new Blob([this.xbrl], { type: 'text/xml' } )

    el[0].files[0] = xml
    el[0].dispatchEvent(new Event('change', {
        bubbles: true,
        target: {
            files: [xml],
        }
    }))
})

@dziamid
Copy link

dziamid commented Aug 17, 2017

@brian-mann

Once we add native events you'll be able to not just upload files but send native keyboard events, mobile events, and a slew of other things.

Is there any progress on the road to native events? Having to hack around for file uploading, hovering and tabbing is a big deal for us.

@brian-mann
Copy link
Member

Chromium team is still working on multiplex'd debugger support. Implementing native events without this is significantly difficult and there are many edge cases and UI changes we'd have to account for, and then once they do land this, we'd have to fork the code and handle it in a separate way.

I'm still on the side of waiting until this is implemented properly by them. You can essentially achieve most things without native event by firing events directly. You can't do things like tab, but you could always use a different tool just for those tests, while letting Cypress handle all the rest.

You can test file uploads using events directly if your app is using HTML5 API's and its not like an oldschool traditional form.

@dziamid
Copy link

dziamid commented Aug 17, 2017

Thanks for the detailed response. While I could get away without tabbing and work around file upload, this involved a lot of boilerplate, complexity and changes in the application code. Nevertheless, great product anyway and good to know that you are looking forward to switching to native events when things get stable on chrome side!

@rdamborsky
Copy link

Using el[0].files[0] = blob as @wescarr recommends worked until few weeks back (I don't recall what Chrome version it was).

But now, at least in v.61+ this no longer works and errors out with "TypeError: Failed to set an indexed property on 'FileList': Index property setter is not supported."

This is not an issue on side of Cypress. I just felt mentioning it might save time to someone running into this thread. Unfortunately, I didn't find a way around this yet.

@brian-mann
Copy link
Member

Haven't looked into this, but oftentimes you can overwrite things manually using Object.defineProperty which can forcibly change the descriptor for values.

That is of course if it's configurable: true

@robrkerr
Copy link

I'm having the same issue @rdamborsky mentioned and can't find a way around it.

@jennifer-shehane jennifer-shehane added the stage: proposal 💡 No work has been done of this issue label Oct 26, 2017
@aboutlo
Copy link

aboutlo commented Oct 27, 2017

@brian-mann I tried to overwrite but it seems not possible:
https://stackoverflow.com/questions/1711357/how-would-you-overload-the-operator-in-javascript

The FileList descriptor is empty
Object.getOwnPropertyDescriptors($input[0].files) // => {}

Any suggestion to get a file upload tested? Perhaps we could pass an option to the cypress run command to turn off chrome security sandbox?

@brian-mann
Copy link
Member

As mentioned above - there is no way to set values in file upload inputs, and there are no flags that chrome exposes to force this. You have to use native events. I commented on this recently yesterday.

#311 (comment)

The only other way to get file uploads working today is to understand how your application handles them with File API and then stub it out. It's possible but not generic enough to give any advice on it.

@aboutlo
Copy link

aboutlo commented Oct 30, 2017

tks @brian-mann 👍

@rafiek
Copy link

rafiek commented Nov 16, 2017

I think Cypress is really awesome and am already using it within my company. We previously used Protractor and were able to add a file to an input[type="file"] element. Would really love to be able to this as well with Cypress, because it is sometimes an essential step when doing full e2e tests for our applications.

@anned20
Copy link

anned20 commented Nov 16, 2017

Hey everyone!

I fixed this for DropZone using this piece of code:

const dropEvent = {
    dataTransfer: {
        files: [
        ],
    },
};

cy.fixture('Path to picture fixture').then((picture) => {
    return Cypress.Blob.base64StringToBlob(picture, 'image/jpeg').then((blob) => {
        dropEvent.dataTransfer.files.push(blob);
    });
});

cy.get('Your dropzone element').trigger('drop', dropEvent);

I hope this will work for you too!

@brian-mann
Copy link
Member

@anned20 this is really good - thank you for this.

One tidbit - you're missing a return statement on Cypress.blob.base64StringToBlob because that returns a promise and the cypress cy.then needs to know about it else it will not properly await it. This is working in your example by chance because the blob promise is resolving faster than the later cy.get and cy.trigger resolve.

Return the promise will always finish the promise chain first before moving on.

@anned20
Copy link

anned20 commented Nov 16, 2017

@brian-mann I updated the example, is this what you meant?

@brian-mann
Copy link
Member

Yup 👍

@vicusbass
Copy link

Is there any workaround (other than using Electron) for file inputs (the dropzone example is not working for me) or we have to wait for the native events implementation?

@brian-mann
Copy link
Member

The workaround is however your application is built. You fire the events and provide the object value properties and/or methods that you application uses to respond to the upload events.

There is no generic solution - you have to understand how your application works. Then however it works you fire what it needs to respond.

@danceric0919
Copy link

danceric0919 commented Nov 24, 2017

I'm new to Cypress.io and encounter issue when testing upload file implemented by Vue.js
We have a component like following:

<b-form-file id="upload-file" v-model="files[0]" @change="upload(payload)" >
</b-form-file>

I tried
cy.get('#upload-file').trigger('change', somepayload)
but nothing happened

is there any way to trigger change or proper event for application implemented by Vue?

Thanks for any respond.
Cheers.

@bahmutov
Copy link
Contributor

bahmutov commented Nov 27, 2017

@danceric0919 can you just call upload() method on the Vue component around this element? Like load the context from Cypress fixture then call the method? I should maybe make a recipe for this that uses Vue.js - where is b-form-file coming from? Is it a public component?

Ok found it - https://bootstrap-vue.js.org/docs/components/form-file/

@bahmutov
Copy link
Contributor

@danceric0919 can you take a look how I test file upload in bahmutov/vue-vuex-todomvc@deff47a ? Just create a File in your test, set it in the component and trigger change event.

@danceric0919
Copy link

danceric0919 commented Nov 28, 2017

@bahmutov thanks for the reply.
I'll try it later today or tomorrow.
Appreciate 👍

2017/11/29 update
After updating application slightly, your example works in my site.
Really appreciate for the example, it saved my days.

@jackblackCH
Copy link

jackblackCH commented Dec 17, 2021

This e.g works for me mp4 files:

    cy.fixture('../fixtures/test.mp4', 'binary')
      .then(Cypress.Blob.binaryStringToBlob)
      .then((fileContent) => {
        cy.get('input[type="file"]').attachFile({
          fileContent: fileContent,
          filePath: '../fixtures/test.mp4',
          mimeType: 'video/mp4',
        })
       ...

@cypress-bot cypress-bot bot added stage: work in progress stage: needs review The PR code is done & tested, needs review and removed stage: needs review The PR code is done & tested, needs review stage: work in progress labels Dec 17, 2021
@cypress-bot
Copy link
Contributor

cypress-bot bot commented Dec 22, 2021

The code for this is done in cypress-io/cypress#19332, but has yet to be released.
We'll update this issue and reference the changelog when it's released.

@cypress-bot cypress-bot bot removed the stage: needs review The PR code is done & tested, needs review label Dec 22, 2021
@BlueWinds
Copy link
Contributor

As an update, we've merged this into the 10.0 release, but it will actually go out in 9.3, scheduled for early January.

@cypress-bot
Copy link
Contributor

cypress-bot bot commented Jan 14, 2022

The code for this is done in cypress-io/cypress#19524, but has yet to be released.
We'll update this issue and reference the changelog when it's released.

@cypress-bot cypress-bot bot added stage: pending release and removed stage: needs review The PR code is done & tested, needs review labels Jan 14, 2022
@tnrich
Copy link
Contributor

tnrich commented Jan 18, 2022

A heads up that the changelog link to the blog about the new functionality is broken:

https://cypress.io/blog/2022/01/18/uploading-files-with-selectfile/

image

@cypress-bot
Copy link
Contributor

cypress-bot bot commented Jan 18, 2022

Released in 9.3.0.

This comment thread has been locked. If you are still experiencing this issue after upgrading to
Cypress v9.3.0, please open a new issue.

@cypress-bot cypress-bot bot locked as resolved and limited conversation to collaborators Jan 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.