skip to content

Locators and Auto-Waiting

How you name an element in the page, how the framework decides it is ready, and the call that finally acts on it. Interviewers start here because the locator model is Playwright's core idea.

on this pageshow

explore

questions

page 1 of 2

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, how does locator.fill() differ from locator.pressSequentially() in what the page receives?

level: juniorimportance: must knowfreq 82%

basics

~20 s

locator.fill() focuses the field, selects any existing text and replaces it in one insertion, firing a single input event. locator.pressSequentially() sends keydown, keypress, input and keyup per character and does not clear the field first.

open as a page

In Playwright, what does locator.press('Control+Enter') send to the page, and how are key names resolved?

level: juniorimportance: must knowfreq 71%

basics

~10 s

locator.press focuses the matched element, holds Control, presses and releases Enter, then releases Control. The argument is one logical key name or a single character, with modifiers joined by plus signs.

open as a page

In Playwright, what must be true of an element before locator.click() actually clicks it?

level: juniorimportance: must knowfreq 82%

basics

~20 s

Playwright retries a set of actionability checks until they all pass or the call times out: the element must be visible, stable in position, able to receive pointer events at the click point, and enabled.

open as a page

In Playwright, what does locator.filter({ hasText: 'Blocked' }) return compared with the locator it was called on?

level: juniorimportance: must knowfreq 78%

basics

~20 s

A new locator matching the same kind of elements, minus the ones whose subtree lacks that text. The original locator is untouched, the match stays on the outer elements, and a string is matched case-insensitively as a substring.

open as a page

In Playwright, how do you click a button that renders inside an iframe?

level: juniorimportance: must knowfreq 74%

basics

~20 s

Call page.frameLocator with a selector for the iframe, then chain the element locator onto it. Everything after the frame locator resolves inside that iframe, and locators built from page are unaffected, so there is nothing to switch back.

open as a page

In Playwright, what is the difference between a Locator and an ElementHandle?

level: juniorimportance: must knowfreq 76%

basics

~10 s

A Playwright Locator stores a recipe for finding an element and re-runs it on every use. An ElementHandle points at one DOM node captured once, so it breaks when the page re-renders that node.

open as a page

In Playwright, what does page.goto() wait for before it resolves?

level: juniorimportance: must knowfreq 78%

basics

~10 s

page.goto() resolves when the load event fires on the new document. The waitUntil option moves that gate to domcontentloaded, commit, or the discouraged networkidle, and the call returns the main resource response.

open as a page

In Playwright, what does page.getByRole('heading', { name: 'Issue 42' }) actually match?

level: juniorimportance: must knowfreq 86%

basics

~20 s

page.getByRole('heading', { name: 'Issue 42' }) matches an element whose ARIA role is heading, implicit for h1 to h6 or set by a role attribute, and whose computed accessible name contains the text Issue 42.

open as a page

In Playwright, how does page.locator() decide whether an unprefixed selector string is CSS or XPath?

level: juniorimportance: must knowfreq 72%

basics

~20 s

Playwright reads an unprefixed string as XPath when it starts with // or .. , as a text selector when the whole string is quoted, and as CSS otherwise. Write css= or xpath= to remove the guess.

open as a page

In Playwright, what is a strict mode violation and when does a locator raise one?

level: juniorimportance: must knowfreq 82%

basics

~20 s

Playwright locators are strict: any call that targets a single DOM element throws a strict mode violation when the locator matches more than one. The error names the locator, the match count, and the candidates it found.

open as a page

In Playwright, what is the difference between page.getByText('Open') and page.getByText('Open', { exact: true })?

level: juniorimportance: must knowfreq 78%

basics

~10 s

By default page.getByText matches a case-insensitive substring of an element's whitespace-normalized text, so Open also matches Reopened. With exact set to true the whole string must match, case-sensitively. Whitespace is normalized either way.

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, which ways can locator.selectOption() identify the option it should select?

level: middleimportance: must knowfreq 66%

basics

~20 s

A plain string matches an option by its value or its label. An object narrows by value, label or index, and every property you state must match. An array selects several options in a multiple select.

open as a page

In Playwright, what do button, modifiers, position, clickCount and delay change about locator.click()?

level: middleimportance: must knowfreq 64%

basics

~20 s

They reshape one synthetic mouse gesture: which button is pressed, which modifier keys are held, where inside the element's padding box the pointer lands, how many clicks are sent, and the pause between mousedown and mouseup.

open as a page

In Playwright, when do you use locator.filter({ has }) instead of chaining locator.locator() to reach an element?

level: middleimportance: must knowfreq 66%

basics

~20 s

Use filter with has when the element you act on is the container and the inner locator is only a test. Chain locator.locator when the target is the descendant itself. Either way the inner locator is relative to the outer match.

open as a page

In Playwright, why does page.getByRole('button', { name: 'Save' }) also match a button named 'Save and close'?

level: middleimportance: must knowfreq 74%

basics

~10 s

The name option is a case-insensitive substring test against the accessible name by default, so any name containing Save matches. Pass exact: true for a case-sensitive whole-string match, or a RegExp for full control.

open as a page

Why does Playwright's locator.click() throw on two matches while locator.count() returns 2 happily?

level: middleimportance: must knowfreq 64%

basics

~20 s

Strictness applies only to calls that need one target element. A click must choose a single element, so two matches is ambiguous and throws. Counting is defined over the whole matched set, so two is simply the answer it returns.

open as a page

Why does Playwright's page.getByTestId offer no exact option when page.getByText and page.getByLabel both do?

level: middleimportance: must knowfreq 68%

basics

~10 s

Because a test id match is always exact. page.getByTestId compares the whole attribute value case-sensitively, so there is nothing for an option to relax. It reads data-testid unless the testIdAttribute option names another attribute.

open as a page

Your Playwright dragTo() leaves an issue-board card in place. How do you diagnose it and hand-build the drag?

level: seniorimportance: must knowfreq 46%

basics

~20 s

dragTo moves to the source, presses, moves to the target and releases. A board built on HTML5 drag and drop needs at least two mouse moves before dragover fires, so rebuild the gesture and hover the target twice.

open as a page

How do you use a Playwright timeout error's call log to find which actionability check never passed?

level: seniorimportance: must knowfreq 58%

basics

~20 s

Read the call log printed under the error. It replays the attempt in order and stops at the condition that never held - element is not visible, not stable, not enabled, or a named node that intercepts pointer events.

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, what does locator.setChecked(true) do that a plain click on the checkbox does not?

level: middleimportance: should knowfreq 54%

basics

~20 s

setChecked reads the control's current state first, clicks only if it differs, and then verifies the new state. A plain click toggles blindly, so an already-checked box ends up unchecked and an intercepted click passes silently.

open as a page

In Playwright, how does locator.dispatchEvent('click') differ from locator.click(), and when is it wrong?

level: middleimportance: should knowfreq 43%

basics

~20 s

locator.click drives a real pointer to the element and sends mousedown and mouseup. dispatchEvent builds a synthetic event in the page and fires it straight at the node, whatever its visibility, with no pointer, no coordinates and isTrusted false.

open as a page

In Playwright, why does locator.fill() succeed on an input covered by an overlay when locator.click() times out?

level: middleimportance: should knowfreq 46%

basics

~10 s

Different actions require different checks. Filling waits only for visible, enabled and editable, then sets the value directly. Clicking additionally requires stability and a hit test at the click point, which the overlay fails.

open as a page

In Playwright, what is the difference between locator.and() and locator.or() when combining two locators?

level: middleimportance: should knowfreq 42%

basics

~20 s

and() is an intersection: one element must satisfy both locators. or() is a union: an element matching either one qualifies. Use and() to pin down a single element by two properties, and or() to wait for whichever of two outcomes appears.

open as a page

What do Playwright's locator.contentFrame() and frameLocator.owner() do?

level: middleimportance: should knowfreq 38%

basics

~20 s

They convert between the two views of an iframe. locator.contentFrame() turns a Locator for the iframe element into a FrameLocator for the document inside it, and frameLocator.owner() turns a FrameLocator back into a Locator for the iframe element.

open as a page

What does Playwright's locator.elementHandle() do before it returns a handle?

level: middleimportance: should knowfreq 38%

basics

~20 s

It waits for the locator to resolve to exactly one attached element and returns a handle to that DOM node. It waits for attachment only, not visibility, and throws when several elements match or when the timeout expires.

open as a page

Why does Playwright mark page.$() and page.$$() as discouraged?

level: middleimportance: should knowfreq 46%

basics

~20 s

Both query once and return handles to whatever exists at that instant: page.$() resolves to null when nothing matches and page.$$() to an empty array, with no waiting. Locators re-resolve and auto-wait instead, so these two calls reintroduce flakiness.

open as a page

Why does Playwright discourage waiting on the networkidle load state in tests?

level: middleimportance: should knowfreq 62%

basics

~20 s

networkidle resolves only after 500 ms with no network connections, which is a proxy for readiness that a polling or streaming app never satisfies. Playwright marks it discouraged and tells you to assert on the rendered result instead.

open as a page

showing 1–30 of 59