Intermediate Chapter 11 · 11 min read

File Upload & Download

Handle file upload inputs and capture downloaded files in Playwright without interacting with OS dialogs.

Uploading Files

File uploads in web applications use a hidden <input type="file"> element. Clicking it would normally open a native OS file-picker that automated tools cannot interact with. Playwright bypasses this entirely with setInputFiles(), which sets the file list directly on the input element. You can pass a single file path, an array of paths for multi-file uploads, or an object with a buffer and filename for in-memory file creation.

Tip: Some applications hide the <input type="file"> and style a custom button. Use page.locator('input[type="file"]') to target the hidden input directly, even if it is not visible.

Downloading Files

Playwright captures downloads by listening for the download event. Like popups and dialogs, you must start waiting for the event before triggering the download action. The Download object provides the suggested filename, the MIME type, and a stream or path to the downloaded content. Use download.saveAs(path) to persist it to a known location for post-test assertions.

Verifying Downloads

After saving, you can read the file content with Node.js fs, Python's built-in open(), or Java's Files.readAllBytes() to validate that the correct data was exported. This makes download testing fully automated and reproducible in CI environments.

upload-download.spec.js
import { test, expect } from '@playwright/test';
import path from 'path';
import fs from 'fs';

test('upload a single file', async ({ page }) => {
  await page.goto('/upload');

  // Target the hidden file input directly
  await page.locator('input[type="file"]')
    .setInputFiles('./fixtures/sample.pdf');

  await expect(page.getByText('sample.pdf')).toBeVisible();
  await page.getByRole('button', { name: 'Upload' }).click();
  await expect(page.getByText('Upload complete')).toBeVisible();
});

test('upload multiple files', async ({ page }) => {
  await page.goto('/upload');
  await page.locator('input[type="file"]').setInputFiles([
    './fixtures/report-jan.csv',
    './fixtures/report-feb.csv',
  ]);
  await expect(page.getByText('2 files selected')).toBeVisible();
});

test('download a file and verify content', async ({ page }) => {
  await page.goto('/reports');

  // Start expecting download before triggering it
  const [download] = await Promise.all([
    page.waitForEvent('download'),
    page.getByRole('button', { name: 'Export CSV' }).click(),
  ]);

  const savePath = `/tmp/${download.suggestedFilename()}`;
  await download.saveAs(savePath);

  const content = fs.readFileSync(savePath, 'utf-8');
  expect(content).toContain('Date,Revenue');
});
FileUploadDownloadTest.java
import com.microsoft.playwright.*;
import java.nio.file.*;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;

class FileUploadDownloadTest {
  void uploadFile(Page page) {
    page.navigate("/upload");
    page.locator("input[type='file']")
        .setInputFiles(Paths.get("fixtures/sample.pdf"));
    assertThat(page.getByText("sample.pdf")).isVisible();
    page.getByRole(AriaRole.BUTTON,
        new Page.GetByRoleOptions().setName("Upload")).click();
    assertThat(page.getByText("Upload complete")).isVisible();
  }

  void downloadFile(Page page) throws Exception {
    page.navigate("/reports");
    Download download = page.waitForDownload(() ->
      page.getByRole(AriaRole.BUTTON,
          new Page.GetByRoleOptions().setName("Export CSV")).click()
    );
    Path savePath = Paths.get("/tmp/" + download.suggestedFilename());
    download.saveAs(savePath);
    String content = new String(Files.readAllBytes(savePath));
    assert content.contains("Date,Revenue");
  }
}
test_file_upload_download.py
from playwright.sync_api import Page, expect
from pathlib import Path

def test_upload_single_file(page: Page):
    page.goto("/upload")

    # Target hidden file input
    page.locator('input[type="file"]').set_input_files("fixtures/sample.pdf")

    expect(page.get_by_text("sample.pdf")).to_be_visible()
    page.get_by_role("button", name="Upload").click()
    expect(page.get_by_text("Upload complete")).to_be_visible()

def test_upload_multiple_files(page: Page):
    page.goto("/upload")
    page.locator('input[type="file"]').set_input_files([
        "fixtures/report-jan.csv",
        "fixtures/report-feb.csv",
    ])
    expect(page.get_by_text("2 files selected")).to_be_visible()

def test_download_and_verify(page: Page):
    page.goto("/reports")

    with page.expect_download() as dl_info:
        page.get_by_role("button", name="Export CSV").click()

    download = dl_info.value
    save_path = Path("/tmp") / download.suggested_filename
    download.save_as(save_path)
    assert "Date,Revenue" in save_path.read_text()

Playwright Intermediate File Upload & Download

Written by PV

© 2026 All Rights Reserved