Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use Cypress’s .selectFile() command to test a file upload through the browser, and trigger the application’s download action before checking the saved file with cy.readFile(). For a file that already exists in your project, pass its project-relative path directly to .selectFile(). Browser-triggered downloads are saved to Cypress’s downloadsFolder, which defaults to cypress/downloads.

Upload a file through a file input

For a UI test that exercises the browser file picker behavior, select the file input and call .selectFile() with a path relative to the project root:

cy.get('input[type="file"]')
  .selectFile('cypress/fixtures/example.pdf')

This is Cypress’s documented approach for files on disk and avoids many encoding-related pitfalls. The command must be chained from a command that yields a DOM element. In ordinary selection mode, that element should be one input[type="file"] or a connected label. See the Cypress .selectFile() documentation.

Upload one or more files

To upload multiple files, pass an array of paths:

cy.get('input[type="file"]')
  .selectFile([
    'cypress/fixtures/first.pdf',
    'cypress/fixtures/second.pdf'
  ])

The input must have the multiple property for an array upload to work. Otherwise, Cypress reports an error.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Upload a fixture as binary data

Use cy.fixture() when test data is fixed and reused. For binary files such as images, request null encoding so Cypress yields a buffer, then pass its alias to .selectFile():

cy.fixture('images/avatar.png', null).as('avatar')
cy.get('input[type="file"]').selectFile('@avatar')

Fixtures are cached for a given path and encoding. By contrast, cy.readFile() is intended for files that can change during a test or that the application creates.

Supply generated content and a filename

For dynamically generated content, provide an object with contents and a meaningful fileName. You can also set mimeType and lastModified when the application depends on them:

const contents = Cypress.Buffer.from('name,emailnAda,ada@example.comn')

cy.get('input[type="file"]').selectFile({
  contents,
  fileName: 'contacts.csv',
  mimeType: 'text/csv',
  lastModified: new Date('2024-01-01T00:00:00Z').getTime()
})

contents can be a string, TypedArray or Cypress.Buffer, a path, or an alias. Cypress can infer a MIME type from a recognized extension; set it explicitly if the test needs a particular value. If omitted, lastModified defaults to the current time. The API page records TypedArray and mimeType support from Cypress 9.4.0.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Test drag-and-drop uploads

If the application accepts dropped files, use the drop target as the subject and set action to drag-drop:

cy.get('[data-cy="drop-zone"]')
  .selectFile('cypress/fixtures/example.pdf', { action: 'drag-drop' })

If the drop handler is attached to the page rather than a specific zone, use body as the subject. Drop events bubble to document-level listeners, so this can cover applications that wire the handler at page level.

Choose an upload source and interaction

What the test needs to exercise Use
An existing project file through the browser UI A project-relative path passed directly to .selectFile().
Fixed test data reused by the test cy.fixture(); use null encoding for binary data.
Generated file contents A .selectFile() object with contents and an explicit filename.
A drop target rather than a file input .selectFile() with { action: 'drag-drop' }.
An upload endpoint, without testing browser file selection cy.request() with multipart form data.

Upload directly to an API instead of using the browser

If the test is specifically about the server’s upload endpoint, use cy.request() with FormData. This tests the API path, not the application’s file-picker or drag-and-drop UI. Cypress preserves the file bytes and supplies the multipart boundary; do not set form, which is for URL-encoded forms. See the Cypress request documentation.

The exact request setup depends on the endpoint and the project’s test environment. Construct the multipart body with the file bytes and the field names your endpoint expects, then send it with cy.request(); do not substitute a URL-encoded form for a multipart upload.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Trigger a browser download and assert on the file

For a UI download test, trigger the application’s download control, then read the predictable output from downloadsFolder and assert on a meaningful requirement:

cy.get('[data-cy="export"]').click()
cy.readFile('cypress/downloads/report.csv')
  .should('contain', 'Total')

Cypress saves browser-triggered downloads without opening the browser’s native Save As dialog or download shelf. The documented default downloadsFolder is cypress/downloads. Pick an assertion that fits the format and requirement: expected text for a CSV, parsed fields for JSON, or exact bytes or encoding where those matter. cy.readFile() can use an explicit encoding or null to yield a Buffer, and retries chained assertions while rereading the file. See the Cypress readFile documentation and test organization documentation.

Configure the download folder and account for cleanup

Set downloadsFolder in Cypress configuration if your tests need a different location. Cypress’s trashAssetsBeforeRuns option defaults to true; before cypress run, it clears downloads, screenshots and videos folders, including nested subfolders. Do not rely on downloaded files remaining from an earlier run. Cypress lists cypress/downloads/, cypress/screenshots/ and cypress/videos/ as generated folders commonly ignored in source control.

Save an HTTP response to disk without testing browser downloads

If the test needs to verify an endpoint response rather than the browser’s download behavior, request the endpoint and write its response to a file. For binary responses such as PDFs, use binary encoding so the bytes are not converted as text:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
cy.request({
  url: '/api/report.pdf',
  encoding: 'binary'
}).then((response) => {
  cy.writeFile('cypress/downloads/report.pdf', response.body, 'binary')
})

Adapt the URL and authentication to your application. cy.writeFile() also accepts a Buffer and null encoding for byte-preserving writes. For Node-side file operations or large-file metadata checks that do not require browser transfer, Cypress documents cy.task(); an official custom-command example uses a task to implement a download command. See the writeFile documentation and task documentation.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot common upload and download failures

  • The file input was not found or the command has the wrong subject: confirm the selector yields one input[type="file"] or a connected label, and that it is present before calling .selectFile().
  • The application uses a hidden file input: if the visible upload control activates that input and Cypress actionability blocks the test, use { force: true } with .selectFile(). Prefer ordinary actionability checks when they match the user interaction.
  • The path or alias cannot be resolved: verify the project-relative path and filename, or confirm the fixture alias was created before it is used. Cypress waits for an existing path, but the command can time out if the path or alias does not resolve.
  • An array upload fails: check that the input has the multiple property. Multiple paths are not accepted by a single-file input.
  • The uploaded file has unexpected text or corrupted binary contents: use a project path directly for an existing file, or load binary fixture data with null encoding and pass a Buffer. Avoid converting binary data to a string unnecessarily.
  • A download assertion runs before the file is available: use cy.readFile() chained with a retryable assertion against the expected file. Confirm the application action actually initiates a download and that the filename and configured folder match.
  • A previous run’s download is missing: account for trashAssetsBeforeRuns, which defaults to clearing asset folders before cypress run.

Cypress notes that .selectFile() follows actionability rules and retries while waiting for an existing path. Its API history records the command as added in Cypress 9.3.0 and a scrollBehavior option change in 15.20.0. The cy.readFile() history records it became a query in Cypress 13.0.0. These are API history markers, not a statement of the latest Cypress release.

Or skip the browser setup

If your goal is to capture a page rather than test your own application’s file workflow, ScreenshotNeo is a website screenshot API and MCP server. One GET request can return a PNG, JPEG, WebP, or PDF. The API removes known cookie/consent banners, newsletter popups and chat widgets before capture; bot checks, blank pages and failed loads are not billed. Its MCP server gives AI agents screenshot and page-information tools. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000.

For example, this cURL request captures a page as WebP:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for authentication and options. Sign up for 1,000 free screenshots a month with no card.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.