How to Perform File Download Using Playwright (TypeScript)

File download is one of the most common scenarios in UI automation. Playwright provides built-in support for handling downloads without relying on browser-specific configurations.

This guide explains everything from basic file downloads to advanced scenarios with practical examples.


Prerequisites

Install Playwright:

npm init playwright@latest

Import Playwright:

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

How Playwright Handles Downloads

Whenever a download starts, Playwright creates a Download object.

You can:

  • Wait for the download event
  • Get download information
  • Save the file
  • Verify file name
  • Verify file content
  • Delete downloaded files

The download object provides methods like:

MethodDescription
download.path()Returns downloaded file path
download.saveAs()Save file to custom location
download.suggestedFilename()Returns original filename
download.failure()Returns download failure reason
download.delete()Deletes downloaded file
download.createReadStream()Reads downloaded file

Example Website

Suppose clicking this button downloads a PDF.

<button>Download Report</button>

Example 1: Basic File Download

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

test('Download File', async ({ page }) => {

    await page.goto('https://example.com');

    const downloadPromise = page.waitForEvent('download');

    await page.getByText('Download Report').click();

    const download = await downloadPromise;

    console.log(download.suggestedFilename());

});

What happens?

Click Button
      │
      ▼
Browser Starts Download
      │
      ▼
Playwright Creates Download Object
      │
      ▼
You Can Save or Verify File

Example 2: Save Download to Custom Folder

import path from 'path';

test('Save Download', async ({ page }) => {

    await page.goto('https://example.com');

    const downloadPromise = page.waitForEvent('download');

    await page.locator('#download').click();

    const download = await downloadPromise;

    await download.saveAs(
        path.join('downloads', download.suggestedFilename())
    );

});

Downloaded folder:

Project

│
├── downloads
│      report.pdf
│
├── tests

Example 3: Get File Name

const fileName = download.suggestedFilename();

console.log(fileName);

Output

report.pdf

Example 4: Get Download Path

const path = await download.path();

console.log(path);

Example Output

C:\Users\Deepesh\AppData\Local\Temp\playwright-downloads\12345.pdf

Example 5: Verify Downloaded File Exists

import fs from 'fs';

const filePath = await download.path();

expect(fs.existsSync(filePath!)).toBeTruthy();

Example 6: Verify File Extension

expect(download.suggestedFilename()).toContain('.pdf');

or

expect(download.suggestedFilename()).toMatch(/\.pdf$/);

Example 7: Verify File Size

import fs from 'fs';

const filePath = await download.path();

const stats = fs.statSync(filePath!);

console.log(stats.size);

Assertion

expect(stats.size).toBeGreaterThan(1000);

Example 8: Verify Downloaded CSV Content

import fs from 'fs';

const filePath = await download.path();

const content = fs.readFileSync(filePath!, 'utf-8');

expect(content).toContain('Employee Name');

Example 9: Verify Downloaded Text File

const filePath = await download.path();

const text = fs.readFileSync(filePath!, 'utf-8');

expect(text).toContain('Welcome');

Example 10: Download Multiple Files

const download1 = page.waitForEvent('download');
await page.click('#download1');
const file1 = await download1;

const download2 = page.waitForEvent('download');
await page.click('#download2');
const file2 = await download2;

console.log(file1.suggestedFilename());
console.log(file2.suggestedFilename());

Example 11: Using Promise.all()

This is the recommended approach because it avoids missing the download event.

const [download] = await Promise.all([
    page.waitForEvent('download'),
    page.locator('#download').click()
]);

await download.saveAs(
    `downloads/${download.suggestedFilename()}`
);

Example 12: Verify Download Failure

const failure = await download.failure();

expect(failure).toBeNull();

If download fails

Network Error

or

Cancelled

Example 13: Delete Downloaded File

await download.delete();

Example 14: Read Download Stream

const stream = await download.createReadStream();

stream?.on('data', chunk => {
    console.log(chunk.toString());
});

Example 15: Download After Login

test('Download Invoice', async ({ page }) => {

    await page.goto('https://example.com/login');

    await page.fill('#username', 'admin');
    await page.fill('#password', 'admin123');

    await page.click('#login');

    const [download] = await Promise.all([
        page.waitForEvent('download'),
        page.click('text=Download Invoice')
    ]);

    await download.saveAs(
        `downloads/${download.suggestedFilename()}`
    );

});

Download PDF Example

const [download] = await Promise.all([
    page.waitForEvent('download'),
    page.getByText('Download PDF').click()
]);

expect(download.suggestedFilename()).toContain('.pdf');

Download Excel Example

const [download] = await Promise.all([
    page.waitForEvent('download'),
    page.getByRole('button', { name: 'Export Excel' }).click()
]);

expect(download.suggestedFilename()).toContain('.xlsx');

Download ZIP Example

const [download] = await Promise.all([
    page.waitForEvent('download'),
    page.click('#zip')
]);

await download.saveAs(
    `downloads/${download.suggestedFilename()}`
);

Browser Download Behavior

BrowserSupported
Chromium
Firefox
WebKit

No browser-specific download configuration is required in Playwright.


Best Practices

  • Always use Promise.all() to wait for the download event and trigger the download simultaneously.
  • Save downloads to a dedicated folder (for example, downloads/) to keep test artifacts organized.
  • Verify both the filename and file extension.
  • Validate the file contents whenever possible instead of checking only that a file exists.
  • Clean up downloaded files after the test to avoid consuming unnecessary disk space.
  • Use download.failure() to detect download issues early.
  • Avoid hard-coded delays such as waitForTimeout() when handling downloads.
  • Use download.suggestedFilename() instead of assuming a fixed filename.

Common Interview Questions

1. How do you handle file downloads in Playwright?

Use page.waitForEvent('download') together with the action that triggers the download, preferably inside Promise.all(). Then use the Download object to save or verify the file.


2. Why should you use Promise.all() for downloads?

It ensures Playwright starts listening for the download event before the click occurs, preventing race conditions where the download starts before the listener is attached.


3. How do you save a downloaded file to a custom location?

Use:

await download.saveAs('downloads/report.pdf');

4. How do you verify a file was downloaded successfully?

You can:

  • Check that await download.failure() returns null.
  • Verify the file exists using fs.existsSync().
  • Validate the filename with download.suggestedFilename().
  • Check the file size or inspect its contents.

5. Can Playwright verify the contents of a downloaded file?

Yes. After obtaining the file path with download.path(), use Node.js modules like fs (or libraries such as xlsx for Excel or pdf-parse for PDFs) to read and validate the file contents.


Summary

Playwright’s download API is simple yet powerful. By using the Download object and the Promise.all() pattern, you can reliably automate downloading PDFs, Excel files, ZIP archives, CSVs, and other file types while verifying filenames, sizes, and contents. This approach works consistently across Chromium, Firefox, and WebKit, making it suitable for both functional and end-to-end automation tests.

Leave a Comment