File operations are a key part of end-to-end testing. Whether it’s uploading a document, exporting a report, or verifying that a downloaded file exists, Playwright provides robust APIs to handle these tasks seamlessly.
In this chapter, we’ll cover everything from basic file uploads and downloads to advanced automation techniques, including verifying file contents, managing temporary directories, and simulating drag-and-drop interactions.
1. Uploading files
File uploads are common in forms. Playwright makes it easy using the setInputFiles() method, which simulates selecting files in a file picker.
Example: Simple file upload
import { test, expect } from '@playwright/test';
import path from 'path';
test('upload a single file', async ({ page }) => {
await page.goto('https://the-internet.herokuapp.com/upload');
// Path to your local file
const filePath = path.join(__dirname, 'test-data/sample.txt');
// Upload the file
await page.setInputFiles('input[type="file"]', filePath);
await page.click('#file-submit');
// Verify upload success
const uploadedFile = page.locator('#uploaded-files');
await expect(uploadedFile).toHaveText('sample.txt');
});
What’s happening here:
- Playwright directly interacts with the file input element.
- No native OS file dialogs are needed.
- The file path points to a file on your system.
Pro Tip: Always store test files in a dedicated
/test-data/directory for consistency.
2. Uploading multiple files
You can upload multiple files at once by passing an array of file paths.
const files = [
path.join(__dirname, 'test-data/sample1.txt'),
path.join(__dirname, 'test-data/sample2.txt')
];
await page.setInputFiles('input[type="file"]', files);
Playwright automatically handles multiple file uploads if the input element allows it (has the multiple attribute).
3. Removing uploaded files
To clear the selected files from an input element, simply call setInputFiles([]).
await page.setInputFiles('input[type="file"]', []);
This resets the input, simulating a user clearing their file selection.
4. Uploading files without visible input
Some web apps hide the <input> element and use a custom button instead. Playwright can still upload files by directly targeting the hidden element.
Example:
await page.setInputFiles('input#hiddenFileInput', 'test-data/image.png');
If your upload button triggers JavaScript validation, make sure to trigger a
changeevent after uploading:
await page.evaluate(() => {
document.querySelector('input#hiddenFileInput').dispatchEvent(new Event('change'));
});
5. Drag-and-drop file uploads (advanced)
Some modern UIs use drag-and-drop areas for uploads. Playwright supports simulating drag-and-drop actions with JavaScript events.
Example:
const filePath = path.join(__dirname, 'test-data/sample.png');
const dataTransfer = await page.evaluateHandle(() => new DataTransfer());
await page.locator('input[type="file"]').setInputFiles(filePath);
await page.dispatchEvent('#drop-zone', 'drop', { dataTransfer });
This mimics a real drag-and-drop upload scenario.
6. Handling file downloads
Playwright automatically detects downloads and gives you control to track and validate them.
Example: Simple download
import fs from 'fs';
import path from 'path';
import { test, expect } from '@playwright/test';
test('download a file', async ({ page }) => {
await page.goto('https://the-internet.herokuapp.com/download');
const [download] = await Promise.all([
page.waitForEvent('download'), // Wait for the download to start
page.click('a[href="download/sample.png"]') // Trigger download
]);
// Save the file to a specific location
const downloadPath = await download.path();
const fileName = download.suggestedFilename();
console.log(`Downloaded: ${fileName}`);
// Optionally save to a custom path
const savePath = path.join(__dirname, 'downloads', fileName);
await download.saveAs(savePath);
// Verify the file exists
expect(fs.existsSync(savePath)).toBeTruthy();
});
What’s happening here:
page.waitForEvent('download')listens for a download trigger.- Playwright saves the file to a temporary location.
- You can save it permanently using
download.saveAs().
7. Accessing download metadata
You can extract metadata like file name, MIME type, and URL.
console.log(await download.url());
console.log(download.suggestedFilename());
console.log(await download.failure()); // Returns error if download failed
Pro Tip: Use
download.failure()to verify whether the download succeeded, it is helpful in negative test cases.
8. Verifying downloaded file contents
You can verify downloaded files by reading them from the filesystem.
Example:
import fs from 'fs';
const filePath = await download.path();
const content = fs.readFileSync(filePath, 'utf8');
expect(content).toContain('Expected Text');
This ensures the downloaded file contains expected data, not just the correct file name.
9. Setting default download directories
You can configure the browser context to store all downloads in a specific folder.
Example:
const context = await browser.newContext({
acceptDownloads: true,
downloadsPath: 'downloads/'
});
Now all downloads automatically save to that directory.
10. Handling failed or interrupted downloads
If a file fails to download, you can capture that using Playwright’s built-in failure detection.
Example:
const [download] = await Promise.all([
page.waitForEvent('download'),
page.click('#export-button')
]);
const error = await download.failure();
if (error) {
console.error('Download failed:', error);
}
This helps diagnose network issues or broken download links.
11. Cleaning up temporary files
When Playwright downloads files, they’re stored temporarily. You can manage these files manually for clean test runs.
Example:
const tempPath = await download.path();
if (fs.existsSync(tempPath)) {
fs.unlinkSync(tempPath); // Delete temporary file
}
12. Best practices for handling files
- Use a dedicated
test-data/directory for uploads. - Use
acceptDownloads: truewhen testing downloads. - Always verify downloaded file existence or content.
- Avoid hardcoded file paths, use
path.join()for cross-platform compatibility. - Clean up downloaded or temporary files after tests.
- Mock file upload/download APIs when testing offline.
Exercise
Task 1: Upload a text file and verify success.
Task 2: Upload multiple files using setInputFiles().
Task 3: Download a file and verify it exists.
Task 4: Read a downloaded file and assert its content.
Bonus: Simulate a drag-and-drop upload.
Cheat Sheet
| Task | Method |
|---|---|
| Upload single file | page.setInputFiles('input', 'file.txt') |
| Upload multiple files | page.setInputFiles('input', ['a.txt', 'b.txt']) |
| Clear upload | page.setInputFiles('input', []) |
| Wait for download | page.waitForEvent('download') |
| Save file | download.saveAs('path/file.txt') |
| Get file path | await download.path() |
| Verify file exists | fs.existsSync(path) |
| Set download directory | browser.newContext({ downloadsPath }) |
Summary
In this chapter, you learned how to:
- Upload single and multiple files using
setInputFiles(). - Handle downloads and track them using
waitForEvent('download'). - Save, verify, and clean up downloaded files.
- Simulate advanced interactions like drag-and-drop uploads.
With Playwright’s file-handling capabilities, you can easily automate workflows involving file uploads and downloads, it’s a critical part of real-world end-to-end testing.
