Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11In Playwright, “load a local file” usually means uploading a fixture through an <input type="file">. For an existing input, call setInputFiles() on a locator. If a click creates the input dynamically, wait for the filechooser event and call setFiles(). Downloads use a different API: wait for the download event and save the file before the browser context closes. Rendering local HTML with setContent() is another workflow entirely.
Choose the Playwright workflow first
The right API depends on what “load” means in your test:
| Goal | Use | What it does |
|---|---|---|
| Upload an existing fixture | locator.setInputFiles() |
Assigns one or more files to an existing file input. |
| Upload after a button creates an input | page.waitForEvent('filechooser') and chooser.setFiles() |
Captures the file chooser triggered by the action, then assigns files. |
| Generate a file in memory | setInputFiles({ name, mimeType, buffer }) |
Uploads bytes without creating a fixture on disk. |
| Test a browser download | page.waitForEvent('download') and download.saveAs() |
Saves the downloaded attachment to a persistent path. |
| Render an HTML string | page.setContent(html) |
Writes supplied markup into the frame; it is not a file upload. |
These APIs do not establish a universal recipe for navigating to arbitrary file:// URLs or serving a project directory. Such behavior depends on the browser, runtime, permissions, and how the local assets reference one another. Treat local-file navigation as a separate, environment-specific problem.
Upload a local file with a known input
Use a locator that targets the actual file input, preferably through its associated label. The path may be relative or absolute. Relative paths are resolved from the process’s current working directory, so make the test runner’s working directory explicit or construct an absolute path.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
#1 Best Overall
JavaScript or TypeScript
import path from 'node:path';
const fixture = path.join(process.cwd(), 'fixtures', 'document.pdf');
await page.getByLabel('Upload file').setInputFiles(fixture);
// Continue with the assertion that proves the page accepted the file.
await expect(page.getByText('document.pdf')).toBeVisible();
If the input has no accessible label, use another stable locator, such as page.locator('input[type="file"]') or a test identifier. Avoid selecting a visible button when the page already exposes a regular input; setInputFiles() is more deterministic than opening an operating-system picker.
Python
from pathlib import Path
from playwright.sync_api import expect
fixture = Path.cwd() / "fixtures" / "document.pdf"
page.get_by_label("Upload file").set_input_files(str(fixture))
expect(page.get_by_text("document.pdf")).to_be_visible()
The Python API accepts the same kinds of inputs: a path, multiple paths, a directory where the page permits directory selection, an in-memory payload, or an empty list to clear the selection.
Multiple files and clearing a selection
// Multiple files (the input must allow multiple selection)
await page.getByLabel('Upload files').setInputFiles([
'fixtures/one.txt',
'fixtures/two.txt'
]);
// Clear the input
await page.getByLabel('Upload files').setInputFiles([]);
Passing multiple paths to an input that does not have the multiple attribute can produce a page-side validation error. Clearing with an empty array removes the selected files without editing the DOM yourself.
Upload generated data without a fixture
When test data is short, generated, or sensitive, provide a payload object. The payload needs a filename, a MIME type, and a byte buffer.
Recommended Free Tools
const csv = Buffer.from('id,namen1,Adan', 'utf8');
await page.getByLabel('Import CSV').setInputFiles({
name: 'users.csv',
mimeType: 'text/csv',
buffer: csv
});
The filename and MIME type are visible to the application, so choose values that match the behavior under test. Generate a unique name when the server rejects duplicates; use a fixed name when deterministic assertions are more important.
Rank #2
Handle a dynamically created file chooser
Some applications create an invisible file input only after a user clicks a custom “Choose file” control. Establish the wait before the click; otherwise the event can be missed.
JavaScript or TypeScript
const chooserPromise = page.waitForEvent('filechooser');
await page.getByRole('button', { name: 'Choose file' }).click();
const chooser = await chooserPromise;
await chooser.setFiles('/absolute/path/to/document.pdf');
The same pattern works when the control is a label, menu item, or custom drag-and-drop substitute, provided the action actually opens a browser file chooser.
Python
with page.expect_file_chooser() as chooser_info:
page.get_by_role("button", name="Choose file").click()
chooser = chooser_info.value
chooser.set_files("/absolute/path/to/document.pdf")
For multiple files or generated data, pass the same path list or payload structure described for setInputFiles(). If the click does not trigger a chooser, inspect the page: it may be navigating, opening a modal, or using a drop zone that requires a different application-specific interaction.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsWait for and save a downloaded file
Uploading sends data into the page. A download is emitted by the browser and must be handled with the Download API. Start waiting before the action that triggers the attachment, then save it to a path you control.
const downloadPromise = page.waitForEvent('download');
await page.getByText('Download file').click();
const download = await downloadPromise;
const destination = path.join(process.cwd(), 'artifacts', download.suggestedFilename());
await download.saveAs(destination);
Downloads normally live in a temporary directory and are removed when the browser context closes. Call saveAs() before closing that context if another test, process, or assertion needs the file. Create the destination directory in your test setup and sanitize any filename before using it in a shared artifact location.
Rank #3
Python download example
from pathlib import Path
destination_dir = Path.cwd() / "artifacts"
destination_dir.mkdir(parents=True, exist_ok=True)
with page.expect_download() as download_info:
page.get_by_text("Download file").click()
download = download_info.value
download.save_as(str(destination_dir / download.suggested_filename()))
If the response is an inline preview rather than an attachment, no download event may occur. Assert the resulting page or response instead of waiting indefinitely for a download.
Render supplied HTML with setContent()
To test markup you already have as a string, use:
await page.setContent('Fixture page
');
setContent(html) assigns HTML to the frame and internally calls document.write(). It does not select a local file, upload bytes through a file input, or guarantee that adjacent relative assets from a local directory will resolve. If your test needs CSS, images, scripts, or fonts, decide explicitly how those resources will be served in the test environment.
Paths, fixtures, and test isolation
Make path resolution predictable
- Resolve fixtures from a known project root or the current working directory used by the runner.
- Prefer absolute paths in CI when the runner may start from a different directory.
- Use platform-aware path helpers such as Node’s
path.join()or Python’spathlib.Path; do not concatenate slash strings. - Keep fixture names and generated artifact names deterministic unless uniqueness is part of the test.
Keep tests independent
- Use a fresh temporary artifact directory per test or worker.
- Clear a reusable input with
setInputFiles([])before a second scenario. - Close pages only after downloads have been saved.
- Do not rely on a previous test’s current working directory or downloaded temporary file.
Troubleshooting common failures
“File not found” or an empty upload
Print or log the resolved path, verify the file exists in the worker’s environment, and check the runner’s working directory. A path valid on a developer laptop may not exist in a container or CI checkout.
Locator matches the wrong element
Confirm that the locator resolves to input[type="file"], not a styled button. Use an accessible label or a unique test identifier and assert the locator count when the page contains several upload controls.
The file chooser wait times out
The wait may have been started after the click, or the control may not open a native chooser. Move the event wait before the action and verify the application’s click handler. For a drop zone, follow the application’s documented input mechanism instead.
Only one file is accepted
Check for the input’s multiple attribute and the application’s own validation. Pass one path for a single-file control; do not assume that an array changes the page’s capabilities.
Download disappears after the test
Save it with download.saveAs() while the producing context is still open. Temporary downloads are deleted when that context closes.
Assertions race the upload or download
Wait for a visible page result, network-driven status, or the download event rather than adding arbitrary sleeps. A delay can hide a race and still fail on a slower worker.
Local HTML has missing images or scripts
setContent() writes markup but does not define a project server or a universal local-file policy. Serve assets through a test web server, use URLs that the page can reach, or test the resource loading setup separately for your chosen browser and runtime.
Performance and reliability choices
- Use disk paths for large, reusable fixtures. They avoid rebuilding the same bytes in every test, but require reliable fixture packaging in CI.
- Use in-memory payloads for small or generated cases. They reduce filesystem setup and make edge-case data easy to vary.
- Wait on events, not fixed delays. Event-based synchronization is both faster on a healthy run and less flaky under load.
- Save only the artifacts you need. Persistent copies aid debugging, while unnecessary downloads increase disk usage on parallel workers.
- Keep browser and Playwright versions aligned with your project. The exact signatures and behavior are version-sensitive; check the API documentation for the version installed in your lockfile.
Or skip the browser setup
If your goal is to obtain a clean image or PDF of a URL rather than exercise a Playwright upload flow, ScreenshotNeo provides a one-request screenshot API. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response reports the page verdict and billing status in X-Page-Verdict and X-Billed headers.
Start with cURL (see the ScreenshotNeo documentation):
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients. Its Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Frequently Asked Questions
Can I upload a directory in Playwright?
Python’s documented file-input API covers directory selection when the page’s input is configured for it. Confirm that the input and browser scenario support directory uploads before relying on that behavior.
Should I use a file URL instead of setInputFiles()?
No single rule covers every file URL, browser, and local asset arrangement. Use setInputFiles() for uploads; treat file URL navigation and local asset serving as a separate environment-specific design.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Why does my downloaded filename differ from the link text?
The browser exposes the server-provided suggested filename through download.suggestedFilename(). Use that value, after applying your own path and safety rules, rather than assuming the visible link text is the filename.
Quick Recap
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.

