skip to content

Files and Dialogs

Three actions that finish only when the browser answers back: handing files to an input, catching a download, and replying to a dialog that is otherwise dismissed for you unheard.

on this pageshow

explore

questions

5

In Playwright, how does locator.setInputFiles() attach a file without the OS picker?

level: juniorimportance: must knowfreq 80%

answer

  1. The native picker is unreachable
  2. Set the input's file list directly
  3. One path, many paths, or a buffer
  4. Empty array clears the selection
  5. Relative paths use the working directory

basics

~20 s

Playwright sets the file input's file list directly through the browser protocol instead of driving the native dialog. Pass one path, several paths, an in-memory buffer object, or an empty array to clear the selection.

solid answer

~40 s

`locator.setInputFiles()` targets an `<input type=file>` (or a `<label>` whose associated control is one) and assigns its file list over the browser's remote-debugging connection, so the operating system's picker never opens -- which is what makes uploads driveable at all. It accepts a single path string, an array of paths for an input marked `multiple`, one or more `{ name, mimeType, buffer }` objects that synthesise a file never written to disk, and `[]` to clear a previous selection. Relative paths resolve against the test process's current working directory, not the spec file's folder. For an input carrying `webkitdirectory`, pass a single directory path. Setting files fires the `input` and `change` events, so the issue tracker's attachment list re-renders exactly as it would for a real user.

code

typescript · 19 lines
typescript
import { test, expect } from '@playwright/test';

test('attach files to an issue', async ({ page }) => {
  await page.goto('/issues/ISS-482');
  const input = page.locator('input[type=file]');

  await input.setInputFiles('fixtures/crash-log.txt');
  await expect(page.getByText('crash-log.txt')).toBeVisible();

  await input.setInputFiles({
    name: 'triage.csv',
    mimeType: 'text/csv',
    buffer: Buffer.from('id,title,status'),
  });
  await expect(page.getByText('triage.csv')).toBeVisible();

  await input.setInputFiles([]);
  await expect(page.getByText('triage.csv')).toBeHidden();
});

go deeper

for a junior

Recall the call itself: locator.setInputFiles with a path string, and that no native picker ever opens. Attaching a fixture file and asserting the filename appears is the whole junior bar here.

for a middle

Explain the four argument shapes -- one path, an array, a name/mimeType/buffer object, and an empty array -- and that relative paths resolve against the test process's working directory rather than the spec file.

for a senior

Show judgment about how the input is reached in a real application, and be ready to say what setInputFiles cannot do when the page never renders a file input you can target.

for a principal

Own the convention: whether the suite ships binary fixtures or synthesises files in memory, and how much upload coverage belongs in end-to-end tests versus cheaper layers.

## The picker is not part of the page When a user clicks **Attach file** on an issue, the browser hands control to the operating system. The window that opens is an OS dialog: it has no DOM, no accessible tree the page can reach, and no protocol surface a browser automation tool can drive. Any strategy that begins "click the button, then choose the file" is dead before it starts. `locator.setInputFiles()` sidesteps that dialog entirely. Rather than simulating the user's trip through the file system, it assigns the input element's file list directly over the browser's remote-debugging connection and then lets the `input` and `change` events fire. From the application's point of view a file was chosen; from the test's point of view nothing ever blocked. ## What it can be pointed at The target must be an `<input type=file>`, or a `<label>` whose associated control is one -- Playwright retargets to the control for you, which is why a locator built from the visible label text usually works. Point it at anything else and the call raises an error rather than quietly doing nothing, so a mis-aimed locator shows up as a failure instead of an upload that never happened. Real applications frequently hide the input behind a styled button. That does not change the approach: you target the input element, not the thing the user clicks. ## The four argument shapes | argument | what it does | | --- | --- | | `'fixtures/crash-log.txt'` | attaches one file read from disk | | `['before.png', 'after.png']` | attaches several; the input needs the `multiple` attribute | | `{ name, mimeType, buffer }` | synthesises a file in memory, nothing on disk | | `[]` | clears the current selection | Consequences worth holding onto: - Relative paths resolve against the **current working directory of the test process**, not the folder holding the spec file. Invoking the runner from a subdirectory changes what a relative path means, so anchoring on a path built at runtime removes the surprise. - Passing several files to an input that lacks `multiple` fails loudly instead of attaching only the first one. - The buffer form produces a complete file: `name` is what the application reads as the file's name, `mimeType` is its type, and `buffer` is the bytes. Nothing touches disk, so there is no binary fixture in the repository and nothing to clean up. - An empty array is a real operation, not a no-op. It resets the file list and fires the same events, so the issue tracker's attachment strip re-renders empty. - For an input carrying the `webkitdirectory` attribute, pass a single directory path and the browser expands it into the files underneath. ## A worked shape 1. Locate the input itself, even when it is visually hidden behind a styled control. 2. Call `setInputFiles()` with a path, an array, or a buffer object. 3. Assert on what the application did with it -- the filename in the attachment list, an upload progress row, a submit button that disables while the request is in flight. Step 3 is the step people skip. `setInputFiles()` resolves once the file list is set and the events are dispatched; it does not wait for the application's own upload request to finish. If the very next line submits the comment, the test is racing the network. Assert on a user-visible consequence before moving on. ## When there is nothing to point at Some upload controls never render a reachable input: script creates one, clicks it, and throws it away. Those pages ask the browser for a file picker instead, and Playwright surfaces that request as a page event you can wait for and answer with the same argument shapes. Reach for it only when there is genuinely no input to target -- a plain `setInputFiles()` call has no event ordering to get wrong. ## Failure modes you will actually meet - **Wrong element.** A locator matching the styled button rather than the input produces an error about the element not being a file input. - **Path drift.** Fixture paths that work under one invocation and break under another are almost always working-directory assumptions in disguise. - **Nothing uploaded.** The file list is set correctly, but the application only uploads on a separate submit action the test never performs. - **Stale assertion.** The test asserts the filename before the application has re-rendered, which is a timing bug in the assertion, not in the upload.

  • What happens if you call setInputFiles on an element that is not a file input?
    It throws. The method requires an `input[type=file]`, or a `<label>` whose associated control is one -- Playwright retargets to that control automatically. Anything else fails with an error naming the element, so a mis-aimed locator surfaces as a real failure rather than an upload that silently never happened.
  • How do you attach two files at once to the same input?
    Pass an array of paths, or an array of buffer objects. The input must carry the `multiple` attribute; without it Playwright raises an error rather than quietly attaching only the first file, which is a useful signal that the markup does not support what the test assumes.

saying these in an interview costs you the question

  • Claims Playwright can click buttons in the native OS file dialog
  • Assumes relative fixture paths resolve from the spec file's folder
  • Thinks setInputFiles types a filename into the input like text
  • Believes clearing a selection requires recreating the input
  • Assumes a buffer upload needs a temporary file on disk first
open as a page

In Playwright, what happens to a window.confirm() dialog when no dialog handler is registered?

level: middleimportance: must knowfreq 70%

basics

~10 s

Playwright dismisses it automatically, so confirm() returns false and the click that opened it completes. Registering a dialog listener turns that off: your handler must then accept or dismiss, or the page freezes.

open as a page

In Playwright, why must a test call download.saveAs() before its browser context closes?

level: middleimportance: should knowfreq 57%

basics

~20 s

Playwright streams a download into a temporary location owned by the browser context and deletes it when that context closes. saveAs copies the bytes to a path you control; without it the file is gone once the test ends.

open as a page

In Playwright, how do you attach a file when the page renders no file input to target?

level: seniorimportance: should knowfreq 46%

basics

~10 s

Wait for the page's filechooser event. Start waiting before clicking the control, then call setFiles on the FileChooser Playwright hands you; this works even when script creates the input and discards it.

open as a page

Should a Playwright suite auto-accept every dialog globally, or handle each one in its own test?

level: principalimportance: should knowfreq 35%

basics

~20 s

Handle them per test. A blanket accept-everything handler hides the dialogs a test should be asserting on, and turns a real regression -- a confirmation that stops appearing, or one that names the wrong issue -- into a silent pass.

open as a page