File inputs in browser tests need a different approach from ordinary clicks because the native file picker lives outside the page DOM. Playwright handles that boundary by attaching a local fixture file directly to an <input type="file"> control and letting the page react as if a user selected the file.
The locator-based setInputFiles() method targets the file input through the same selectors used for other actions. Relative file paths are resolved from the current working directory, so upload fixtures should live in predictable project paths such as tests/fixtures/.
Keep upload samples small and safe to commit with the test suite. A browser-side upload check proves that the input received the file and that client-side validation or preview code ran; server-side upload handling still needs a submit action and a response, database, or artifact assertion.
Related: How to run Playwright tests
Related: How to run specific Playwright tests
Steps to upload files in Playwright tests:
- Open the existing Playwright project.
$ cd ~/projects/playwright-demo
Install Playwright first when the project does not already have @playwright/test.
Related: How to install Playwright with npm - Create a directory for upload fixtures.
$ mkdir -p tests/fixtures
- Create a small fixture file.
$ printf "invoice upload sample\n" > tests/fixtures/invoice.txt
- Create tests/file-upload.spec.ts with a file input and upload assertion.
import { test, expect } from "@playwright/test"; import path from "path"; test("uploads invoice fixture", async ({ page }) => { const uploadPath = path.join(process.cwd(), "tests/fixtures/invoice.txt"); await page.setContent(` <label> Upload file <input type="file" name="attachment"> </label> <p id="chosen">No file selected</p> <script> document.querySelector("input").addEventListener("change", event => { const file = event.target.files[0]; document.querySelector("#chosen").textContent = file ? file.name + " (" + file.size + " bytes)" : "No file selected"; }); </script> `); await page.getByLabel("Upload file").setInputFiles(uploadPath); await expect(page.locator("#chosen")).toHaveText("invoice.txt (22 bytes)"); const fileName = await page.getByLabel("Upload file").evaluate( (input: HTMLInputElement) => input.files?.[0]?.name ); expect(fileName).toBe("invoice.txt"); });Replace page.setContent() with page.goto() and the application's upload control when validating a real page. Pass an array to setInputFiles() for a multiple file input, or pass an empty array when a reset test needs to clear the selection.
- Run the upload spec.
$ npx playwright test tests/file-upload.spec.ts Running 1 test using 1 worker ✓ 1 tests/file-upload.spec.ts:4:5 › uploads invoice fixture (482ms) 1 passed (1.4s)
The passing spec confirms that Playwright attached the fixture to the input and that browser-side change handling read the selected file. Add a submit and response assertion when the application must prove server-side storage.
Related: How to run specific Playwright tests
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.