Tests React component that uploads a file. React source is in index.html, spec files in cypress/integration folder. To run tests
npm run cypress:open
- The tests are trying to pass a synthetic test file to upload via an
.trigger('change')
event passingFile
reference using event propertytestFile
. In the source code we try to grab this property before accessing the native file reference (which Cypress cannot set until we can fire the native file upload event)
// application code tries to grab the File reference from "testFile" property
// which is set by the end-to-end Cypress test
const file = e.nativeEvent.testFile || e.nativeEvent.target.files[0]
We can confirm that the file gets uploaded by stubbing either XHR request or intercepting the axios
library method used by the application's code to actually perform the file upload. See the spec.js
how to:
- Stub network calls using
cy.intercept()
- Alternatively stub
axios.post
method usingcy.stub()
- uses
cypress-file-upload
for file upload viainput
event
The most generic way to bypass all native event restrictions is to factor out accessing native change
event to extract the file into the tiniest application method and stub it from the end-to-end test. Here is the relevant application code:
// browser will run "fileUpload" on change event
<input id="file1" type="file" onChange={this.fileUpload}/>
// inside our component's code
fileUpload (e) {
const file = this.getFileToUpload(e)
// upload returned file
},
getFileToUpload (e) {
// either upload file directly from the event (from a test)
// or from the DOM file input list
return e.nativeEvent.testFile || e.nativeEvent.target.files[0]
}
// we set the initialized application instance on the "window" object
// to let test methods access "app.getFileToUpload"
let app = ReactDOM.render(
<FileUploadApp/>,
document.getElementById('app')
);
// if the application is being tested from Cypress
// pass the reference to the application instance
// via "window" object, so the tests can directly interact with the app
if (window.Cypress) {
window.app = app
}
Notice how we factored out accessing the nativeEvent.target.files
into its own JavaScript method getFileToUpload
? This allows us to stub just that application method from the end-to-end test.
const testFile = new File(['data to upload'], 'upload.txt')
// directly stub the application method that returns the File object to upload
cy.window().its('app')
.then((app) => {
cy.stub(app, 'getFileToUpload').returns(testFile)
})
The rest of the application's code runs "normally" without any stubbing.
Check out a blog post that describes this technique in general "Shrink the Untestable Code With App Actions And Effects"
Attaches the CSV fixture using the cypress-file-upload
. The attached file is parsed by the application using the papaparse library. The test then validates the parsed results.