100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Testing

Testing File Uploads

Learn how Cypress's built-in selectFile() command tests file inputs and drag-and-drop uploads, and how to verify the resulting network request.

Advanced TestingIntermediate7 min readJul 10, 2026
Analogies

Uploading Files with cy.get().selectFile()

Since Cypress 9.3, the built-in selectFile() command handles file uploads natively, replacing the community cypress-file-upload plugin that most projects used before that. You call it on the file input element, for example cy.get('input[type=file]').selectFile('cypress/fixtures/avatar.png'), and Cypress attaches the file, sets the input's files property, and fires the appropriate change and input events so any React or Vue onChange handler wired to that input reacts exactly as it would to a real user selecting a file through the OS file picker.

🏏

Cricket analogy: It's like a stadium's Hawk-Eye system now being built directly into the broadcast feed instead of requiring a separate third-party overlay tool bolted on afterward, since the native capability replaced the workaround.

Uploading and Drag-and-Drop

selectFile() also supports simulating drag-and-drop onto a drop-zone element by passing { action: 'drag-drop' }, which is necessary for UI libraries like react-dropzone that listen for dragenter, dragover, and drop events rather than a plain input's change event, for example cy.get('.dropzone').selectFile('cypress/fixtures/report.pdf', { action: 'drag-drop' }). You can also upload multiple files at once by passing an array of paths, and you can supply file content directly as a Buffer or a Cypress.Buffer object instead of a fixture path, which is useful for generating a file dynamically in the test rather than committing a static binary to the repo.

🏏

Cricket analogy: It's like simulating a specific fielding drill (a diving catch) rather than a standard catch drill, because some outfield positions specifically train for that different mechanic, just as drag-drop needs different simulated events than a plain input.

Verifying Upload Results

After triggering the upload, the assertion typically targets one of two things: the UI feedback confirming the file was accepted (a filename chip appearing, a preview thumbnail rendering, an enabled submit button), or the actual network request sent to the backend, which you can intercept with cy.intercept('POST', '/api/upload').as('upload') and then inspect via cy.wait('@upload').its('request.body') to confirm the multipart form data contains the expected file. Asserting on the real request body catches bugs the UI alone might hide, such as the wrong field name being used in the FormData object sent to the server.

🏏

Cricket analogy: It's like checking both the scoreboard display and the official match data feed after a boundary is scored, since the visible scoreboard might glitch even if the underlying data is correct, or vice versa.

javascript
// cypress/e2e/upload.cy.js
describe('Report upload', () => {
  beforeEach(() => {
    cy.intercept('POST', '/api/upload').as('upload');
    cy.visit('/reports/new');
  });

  it('uploads via drag-and-drop and sends the correct multipart field', () => {
    cy.get('.dropzone').selectFile('cypress/fixtures/report.pdf', {
      action: 'drag-drop',
    });

    cy.get('.file-chip').should('contain.text', 'report.pdf');

    cy.wait('@upload').its('request.body').should((body) => {
      expect(body).to.include('name="reportFile"');
      expect(body).to.include('filename="report.pdf"');
    });
  });

  it('uploads a dynamically generated CSV without a fixture file', () => {
    const csvContent = 'id,total\n1,42.50\n2,17.00';
    cy.get('input[type=file]').selectFile({
      contents: Cypress.Buffer.from(csvContent),
      fileName: 'generated-report.csv',
      mimeType: 'text/csv',
    });
    cy.wait('@upload').its('response.statusCode').should('eq', 201);
  });
});

selectFile() accepts a contents option of a Buffer or Cypress.Buffer, which lets a spec generate file content programmatically inside the test itself, avoiding the need to commit large or numerous static binary files to the fixtures folder for every upload variation you want to test.

A path passed to selectFile() is resolved relative to the project root by default, not cypress/fixtures, so a common mistake is passing 'avatar.png' expecting it to resolve automatically — use the full relative path like 'cypress/fixtures/avatar.png', or set the fixturesFolder-relative path explicitly if your config changes the default location.

  • cy.get(selector).selectFile() is the built-in command for testing file uploads since Cypress 9.3, replacing the older cypress-file-upload plugin.
  • selectFile() fires real change/input events so framework onChange handlers behave as with a genuine user selection.
  • Pass { action: 'drag-drop' } to simulate uploads onto drop-zone components that listen for drag events instead of input change.
  • An array of paths uploads multiple files in one call.
  • File contents can be supplied as a Buffer/Cypress.Buffer to generate files dynamically instead of using static fixtures.
  • Assert both UI feedback and the actual intercepted network request body to fully verify an upload.
  • Paths passed to selectFile() resolve relative to the project root, so fixture paths must include the cypress/fixtures prefix.

Practice what you learned

Was this page helpful?

Topics covered

#Testing#CypressStudyNotes#TestingQA#TestingFileUploads#File#Uploads#Uploading#Files#StudyNotes#SkillVeris