Skip to main content
The FileChooser class represents a file upload dialog that appears when the page requests file input. Handle file uploads using the page.on('filechooser') event or by interacting with file input elements directly.

Overview

import { test } from '@playwright/test';

test('upload file', async ({ page }) => {
  const fileChooserPromise = page.waitForEvent('filechooser');
  await page.click('#upload-button');
  
  const fileChooser = await fileChooserPromise;
  await fileChooser.setFiles('./file.pdf');
});

Methods

element()

Get the input element associated with the file chooser. Returns: ElementHandle
const fileChooser = await fileChooserPromise;
const input = fileChooser.element();
console.log(await input.getAttribute('accept'));

isMultiple()

Check if the file chooser accepts multiple files. Returns: boolean Returns true if the input element has the multiple attribute:
const fileChooser = await fileChooserPromise;
if (fileChooser.isMultiple()) {
  console.log('Multiple files can be selected');
}

page()

Get the page that opened the file chooser. Returns: Page
const fileChooser = await fileChooserPromise;
const page = fileChooser.page();
console.log(`File chooser from: ${page.url()}`);

setFiles(files, options?)

Set files for the file chooser.
files
string | FilePayload | string[] | FilePayload[]
required
Path(s) to file(s) or file payload object(s) to upload
options.timeout
number
Maximum time in milliseconds. Defaults to 30000 (30 seconds).
options.noWaitAfter
boolean
default:"false"
If set, don’t wait for the file input to be processed after setting files.
Returns: Promise<void>

File Path

// Single file
await fileChooser.setFiles('./document.pdf');

// Multiple files
await fileChooser.setFiles([
  './file1.pdf',
  './file2.pdf',
]);

File Payload

import { readFile } from 'fs/promises';

const buffer = await readFile('./document.pdf');
await fileChooser.setFiles({
  name: 'document.pdf',
  mimeType: 'application/pdf',
  buffer,
});

// Multiple payloads
await fileChooser.setFiles([
  {
    name: 'file1.txt',
    mimeType: 'text/plain',
    buffer: Buffer.from('Content 1'),
  },
  {
    name: 'file2.txt',
    mimeType: 'text/plain',
    buffer: Buffer.from('Content 2'),
  },
]);

Clear Files

// Clear selection
await fileChooser.setFiles([]);

Examples

Basic File Upload

test('upload single file', async ({ page }) => {
  await page.goto('https://example.com');
  
  const fileChooserPromise = page.waitForEvent('filechooser');
  await page.click('#file-upload-button');
  
  const fileChooser = await fileChooserPromise;
  await fileChooser.setFiles('./document.pdf');
});

Upload Multiple Files

test('upload multiple files', async ({ page }) => {
  const fileChooserPromise = page.waitForEvent('filechooser');
  await page.click('#upload-button');
  
  const fileChooser = await fileChooserPromise;
  
  if (fileChooser.isMultiple()) {
    await fileChooser.setFiles([
      './file1.pdf',
      './file2.pdf',
      './file3.pdf',
    ]);
  }
});

Upload from Buffer

test('upload from buffer', async ({ page }) => {
  const fileChooserPromise = page.waitForEvent('filechooser');
  await page.click('#upload-button');
  
  const fileChooser = await fileChooserPromise;
  
  // Create file from string
  await fileChooser.setFiles({
    name: 'data.json',
    mimeType: 'application/json',
    buffer: Buffer.from(JSON.stringify({ key: 'value' })),
  });
});

Direct Input Element Upload

test('upload via input element', async ({ page }) => {
  await page.goto('https://example.com');
  
  // Set files directly on input element
  await page.setInputFiles('#file-input', './document.pdf');
  
  // Or multiple files
  await page.setInputFiles('#file-input', [
    './file1.pdf',
    './file2.pdf',
  ]);
});

Check Accepted File Types

test('check accepted types', async ({ page }) => {
  const fileChooserPromise = page.waitForEvent('filechooser');
  await page.click('#upload-button');
  
  const fileChooser = await fileChooserPromise;
  const input = fileChooser.element();
  const accept = await input.getAttribute('accept');
  
  console.log(`Accepted types: ${accept}`);
  
  // Upload appropriate file
  await fileChooser.setFiles('./document.pdf');
});

Cancel File Selection

test('cancel file selection', async ({ page }) => {
  const fileChooserPromise = page.waitForEvent('filechooser');
  await page.click('#upload-button');
  
  const fileChooser = await fileChooserPromise;
  
  // Cancel by setting empty array
  await fileChooser.setFiles([]);
});

Upload with Form Submit

test('upload and submit form', async ({ page }) => {
  await page.goto('https://example.com');
  
  // Upload file
  await page.setInputFiles('#file-input', './document.pdf');
  
  // Submit form
  await page.click('#submit-button');
  
  // Wait for upload completion
  await page.waitForSelector('.success-message');
});

Generate Dynamic File

test('upload dynamic file', async ({ page }) => {
  const fileChooserPromise = page.waitForEvent('filechooser');
  await page.click('#upload-button');
  
  const fileChooser = await fileChooserPromise;
  
  // Generate CSV content
  const csvContent = 'Name,Age\nAlice,30\nBob,25';
  
  await fileChooser.setFiles({
    name: 'data.csv',
    mimeType: 'text/csv',
    buffer: Buffer.from(csvContent),
  });
});

Verify Upload

test('verify file upload', async ({ page }) => {
  await page.goto('https://example.com');
  await page.setInputFiles('#file-input', './document.pdf');
  
  // Verify file name appears
  const filename = await page.textContent('.file-name');
  expect(filename).toBe('document.pdf');
  
  // Submit and verify
  await page.click('#submit');
  await expect(page.locator('.success')).toBeVisible();
});

Best Practices

Wait Before Triggering

Set up the file chooser listener before the action:
// Good: Wait first
const fileChooserPromise = page.waitForEvent('filechooser');
await page.click('#upload-button');
const fileChooser = await fileChooserPromise;

// Bad: Race condition
await page.click('#upload-button');
const fileChooser = await page.waitForEvent('filechooser');

Use Promise.all

const [fileChooser] = await Promise.all([
  page.waitForEvent('filechooser'),
  page.click('#upload-button'),
]);
await fileChooser.setFiles('./file.pdf');

Check Multiple Attribute

Verify if multiple files are expected:
const fileChooser = await fileChooserPromise;
const files = fileChooser.isMultiple() 
  ? ['./file1.pdf', './file2.pdf']
  : './file.pdf';
await fileChooser.setFiles(files);

Use setInputFiles for Simple Cases

If you don’t need to intercept the file chooser dialog:
// Simpler approach
await page.setInputFiles('#file-input', './document.pdf');

// Instead of:
const fileChooserPromise = page.waitForEvent('filechooser');
await page.click('#file-input');
const fileChooser = await fileChooserPromise;
await fileChooser.setFiles('./document.pdf');

Verify File Type

Check accepted file types before uploading:
const fileChooser = await fileChooserPromise;
const input = fileChooser.element();
const accept = await input.getAttribute('accept');

if (accept?.includes('.pdf')) {
  await fileChooser.setFiles('./document.pdf');
}

Common Issues

File Chooser Not Triggered

Ensure the file input is properly activated:
// Make sure the element is visible and interactable
await page.locator('#upload-button').waitFor({ state: 'visible' });

const fileChooserPromise = page.waitForEvent('filechooser');
await page.click('#upload-button');
const fileChooser = await fileChooserPromise;

Hidden File Inputs

Some file inputs are hidden with CSS:
// Use setInputFiles directly
await page.setInputFiles('input[type="file"]', './file.pdf', {
  // Force even if hidden
  force: true,
});

File Path Issues

Use absolute paths or paths relative to the test file:
import path from 'path';

const filePath = path.join(__dirname, 'fixtures', 'document.pdf');
await fileChooser.setFiles(filePath);

Type Definitions

FilePayload

interface FilePayload {
  name: string;        // File name
  mimeType: string;    // MIME type
  buffer: Buffer;      // File contents
}

Build docs developers (and LLMs) love