Skip to content
masterclassBuddyTech Buzz5 fresh blogs · 5:00 AM IST

Technology handbook

Playwright — API, Locators, Fixtures & Tooling

104 entries covering the Playwright API: locators, actions, web-first assertions, fixtures, network mocking, configuration and the tracing tools.

Topics
104
Sections
9

Core API

@playwright/test

The test runner: fixtures, parallelism, retries, reporters and assertions in one package.

  • The test runner package supplies test, expect, fixtures and the config.
  • Runner and library ship together, which is why fixtures and assertions align.
  • Importing expect from elsewhere loses the retrying web-first assertions.

playwright

The automation library alone, for scripts and scraping without the runner.

  • The library alone drives browsers without the test runner.
  • It suits scraping and automation where no test structure is wanted.
  • Using it for tests means writing fixtures and reporting yourself.

chromium / firefox / webkit

The three bundled engines. WebKit is the closest available stand-in for Safari.

  • Three engines are bundled and driven through one API.
  • WebKit is the closest available proxy for Safari behaviour.
  • One API does not mean identical behaviour across the three.

browserType.launch

Starts a browser process, with headless, channel, args and slowMo.

  • A browser process starts with options such as headless and slowMo.
  • Launching is expensive, which is why contexts exist to reuse it.
  • A launched browser must be closed or the process survives the run.

browserType.connect

Attaches to a remote browser server, for a grid or a container.

  • A remote browser is driven over a websocket.
  • Connecting is how a browser grid or container is shared.
  • Latency per action rises, which changes how a suite feels.

browser.newContext

An isolated profile — its own cookies, storage and permissions. Cheap, unlike a new browser.

  • An isolated profile is created with its own cookies and storage.
  • Isolation per context is what makes parallel tests independent.
  • A context is cheap; a browser launch is not.

browser.newPage

A tab within a context. Most tests need one page and one context.

  • A page is opened, creating a context implicitly if needed.
  • The implicit context is why state can leak when it is reused.
  • Creating the context explicitly is what gives control over isolation.

BrowserContext

Where isolation lives: storageState, geolocation, permissions, viewport and offline mode.

  • Cookies, storage, permissions and geolocation are scoped here.
  • Storage state is loaded and saved at this level, not per page.
  • Closing it closes every page it owns.

Page

The tab: navigation, locators, evaluation, screenshots and event handling.

  • A single tab is navigated, queried and acted upon.
  • Most of the API hangs off the page, which is the usual entry point.
  • A page belongs to a context, so its state is the context's state.

Frame / FrameLocator

Addresses content inside an iframe, which locators otherwise cannot reach.

  • frameLocator targets elements inside an iframe and waits for the frame to appear.
  • It is strict by default and works with web-first assertions.
  • An ordinary locator cannot cross a frame boundary at all.

Worker

Access to web workers and service workers running in the page.

  • Web workers and service workers are observed and interacted with.
  • A service worker can serve requests that route interception must account for.
  • Workers outlive the page that registered them.

page.goto

Navigates, waiting for load by default. waitUntil changes the condition.

  • A URL is loaded and the navigation awaited.
  • The wait condition decides what counts as loaded.
  • Waiting for full load is slower and often less reliable than waiting for content.

page.evaluate

Runs a function in the page and returns a serialisable result.

  • JavaScript runs in the page and returns a serialisable value.
  • Only serialisable data crosses the boundary, so a DOM node cannot come back.
  • It performs no waiting, so the element must already exist.

page.exposeFunction

Installs a Node callback the page can call, for bridging back out.

  • A Node function is callable from inside the page.
  • It is how page code reports back into the test process.
  • It stays bound for the page's lifetime, including after navigation.

page.addInitScript

Runs a script before any page script — used for stubbing Date, Math.random or feature flags.

  • A script runs before any page script on every navigation.
  • Running first is what allows a global to be stubbed before use.
  • It runs on every navigation, so it must be idempotent.

Locators

page.locator

A lazy, auto-retrying query. It resolves at use time, so it survives re-rendering.

  • A CSS or XPath selector becomes a lazy, retrying locator.
  • Laziness is what lets it be declared before the element exists.
  • A CSS selector breaks on restyling that changed nothing a user sees.

getByRole

The preferred query: matches the accessibility role and name, so it tests what users perceive.

  • Elements are found by accessible role and name.
  • It is the closest match to how assistive technology sees the page.
  • If it cannot find the element, the accessibility tree is probably wrong.

getByText

Matches visible text, exact or substring.

  • An element is matched by its visible text.
  • Matching visible text keeps the test aligned with what users read.
  • It matches substrings by default, which can catch more than intended.

getByLabel

Finds a form control by its associated label — the right way to reach inputs.

  • A form control is found through its associated label.
  • Going through the label is what proves the control is actually labelled.
  • An unlabelled input is invisible to this locator, which is the point.

getByPlaceholder

Matches a placeholder, for inputs that have no real label.

  • An input is matched by its placeholder text.
  • It is a fallback where a real label is absent.
  • Placeholder is not a label, so relying on it hides an accessibility gap.

getByAltText

Matches an image by its alternative text.

  • An image is found by its alternative text.
  • It asserts the image has alt text as a side effect of locating it.
  • Decorative images have empty alt and cannot be found this way.

getByTitle

Matches the title attribute.

  • An element is matched by its title attribute.
  • It is useful for icons that carry no visible text.
  • Title text is not reliably surfaced to users, so it is a weak anchor.

getByTestId

Matches an explicit test id. The escape hatch when no accessible name exists.

  • An element is found by a dedicated test attribute.
  • A test id is the most stable anchor because nothing else uses it.
  • It says nothing about whether the element is usable or accessible.

locator.filter

Narrows a set by contained text or by a nested locator — how you pick one row out of a table.

  • A locator is narrowed by text or by a locator it must contain.
  • Filtering by content identifies a row without depending on its position.
  • It is the documented answer to a strict mode violation on a list.

locator.and / locator.or

Combines locators for elements that must match both, or either, condition.

  • Two locators combine by intersection or alternative.
  • or is what handles a control whose markup differs between states.
  • or resolving to two different elements still violates strict mode.

locator.nth / first / last

Selects by index. A sign the query could be more specific.

  • One element is selected from several matches by position.
  • Position is a last resort when nothing distinguishes them by content.
  • An index reorders the moment the list does.

Strict mode

An action on a locator matching several elements fails rather than picking one. On by default, and correct.

  • A locator resolving to more than one element throws a strict mode violation.
  • The error lists the matching elements, so the fix is visible in the message.
  • Frame locators are strict by default too.

Chaining

page.getByRole('row').getByRole('button') scopes a query inside another match.

  • Locators compose to scope a search within another element.
  • Scoping is what makes a locator unique without a brittle selector.
  • Each link is resolved at use time, not when it was written.

Auto-waiting

Every action waits for the element to be attached, visible, stable and enabled first.

  • Actions wait for the actionability checks: visible, stable, enabled, editable and receiving events.
  • The docs state there are no artificial timeouts — waiting replaces them.
  • dispatchEvent performs no actionability checks at all, which is why it bypasses this.

Actions

click / dblclick

Clicks after the actionability checks, with modifiers, button and position options.

  • A click is dispatched after the element becomes actionable.
  • It waits for the element to stop moving, which manual clicks do not.
  • Forcing a click skips those checks and hides a real problem.

fill

Sets an input's value in one step. Faster and more reliable than typing for most cases.

  • An input's value is set and the input event dispatched.
  • It clears first, so it replaces rather than appends.
  • It does not produce per-key events, which some inputs rely on.

pressSequentially

Types character by character, for inputs with per-keystroke behaviour such as autocomplete.

  • Text is typed one key at a time with real key events.
  • Per-key events are what trigger autocomplete and masking logic.
  • It is far slower than fill, so it is reserved for that need.

press

Sends a single key or chord, such as Control+Enter.

  • A single key or chord is sent to the focused element.
  • It is how Enter, Escape and shortcuts are exercised.
  • The element must be focused, which press does not do by itself.

check / uncheck

Sets a checkbox or radio to a known state, asserting the result.

  • The control is set to a known state rather than toggled.
  • The action performs the actionability checks and then verifies the resulting state.
  • Clicking instead depends on whatever the state was beforehand.

selectOption

Chooses from a native <select> by value, label or index.

  • An option is chosen in a native select by value, label or index.
  • It targets the native element, not a custom dropdown.
  • A styled dropdown needs ordinary clicks instead.

setInputFiles

Attaches files to a file input, including clearing it with an empty array.

  • Files are attached to a file input without a system dialog.
  • Bypassing the dialog is what makes uploads testable.
  • A custom uploader that hides the input needs the file chooser event.

hover

Moves the pointer over an element, for menus and tooltips.

  • The pointer is moved over an element.
  • Hover is what reveals menus and tooltips that only appear on it.
  • Hover state is lost as soon as another action moves the pointer.

dragTo

Drags one element onto another, with manual mouse control available when HTML5 DnD misbehaves.

  • One element is dragged onto another.
  • It issues the pointer sequence a drag implementation expects.
  • HTML5 drag and drop often needs manual events instead.

focus / blur

Moves focus explicitly, for testing keyboard and validation behaviour.

  • Focus is moved to or away from an element.
  • Blur is what triggers validation that runs on leaving a field.
  • Focusing directly skips the tab order a keyboard user would follow.

scrollIntoViewIfNeeded

Scrolls to an element. Rarely needed, since actions scroll on their own.

  • An element is scrolled into the viewport.
  • Actions scroll automatically, so this is for assertions and screenshots.
  • Virtualised lists may not render the element until it is scrolled.

page.keyboard / page.mouse

Low-level input when a locator action is not expressive enough.

  • Low-level input is dispatched without a target element.
  • It is how a drag, a chord or a canvas interaction is composed.
  • There is no auto-waiting, so readiness must be established first.

Assertions

expect(locator).toBeVisible

Web-first assertion that retries until the element is visible or the timeout expires.

  • The assertion retries until it passes or the assertion timeout is reached.
  • Retrying assertions are async, so the docs require them to be awaited.
  • On timeout the error reports the last observed value, not just a failure.

toHaveText / toContainText

Asserts text content, exact or partial, with array forms for lists.

  • toHaveText matches the whole text; toContainText matches a substring.
  • Both retry, so they wait for content to finish rendering.
  • Against several elements they compare an array rather than a concatenation.

toHaveValue

Asserts an input's current value.

  • An input's current value is asserted.
  • Value is not text content, so the text assertions do not apply.
  • It reads the live value, not the value attribute.

toBeEnabled / toBeDisabled

Asserts interactivity, which matters for buttons gated on form state.

  • An element's interactive state is asserted.
  • Disabled state is what a submit button test usually hinges on.
  • An element styled to look disabled is still enabled.

toBeChecked

Asserts checkbox and radio state, including indeterminate.

  • A checkbox or radio state is asserted.
  • It reads the control's real state rather than a class.
  • Indeterminate is a third state neither checked nor unchecked.

toHaveAttribute / toHaveClass

Asserts attributes and classes, with regular expressions allowed.

  • toHaveClass matches the full class property; toContainClass checks for specific classes.
  • toHaveAttribute asserts a DOM attribute value.
  • Class assertions couple the test to styling detail rather than behaviour.

toHaveCount

Asserts how many elements a locator matches — the assertion for list rendering.

  • The exact number of matching elements is asserted, with retries.
  • Retrying is what lets it wait for a list to finish rendering.
  • Zero is a valid count, which is how absence of a list is asserted.

expect(page).toHaveURL

Asserts the current URL, by string or pattern, after navigation.

  • The page's URL is asserted, with retries for navigation.
  • Retrying is what handles a redirect that has not settled.
  • It compares the full URL unless a pattern is used.

expect(page).toHaveTitle

Asserts the document title, by string or pattern, once navigation settles.

  • The document title is asserted.
  • Titles often update after data loads, so retrying matters.
  • It reads the live title, not the server-rendered one.

toHaveScreenshot

Visual comparison against a committed baseline, with masking and a pixel threshold.

  • The rendered appearance is compared against a stored baseline.
  • Masking volatile regions is what stops a clock failing every run.
  • Baselines are platform-specific, so local images rarely match CI.

expect.poll

Retries an arbitrary expression, for state that is not in the DOM.

  • An arbitrary function is polled until it returns the expected value.
  • It brings retrying to values the web-first assertions do not cover.
  • The polled function runs repeatedly, so it must have no side effects.

expect.soft

Records a failure and carries on, so one run reports every problem.

  • A failed assertion records but does not stop the test.
  • Several failures can be reported from one run.
  • The test still fails, so a soft assertion is not an ignored one.

expect.configure

Produces an expect with its own timeout and soft setting.

  • A reusable expect is created with its own timeout or softness.
  • Configuring once avoids repeating options at every call.
  • It returns a new expect rather than changing the global one.

Fixtures & hooks

test.use

Overrides options for a file or a describe block — viewport, locale, storage state.

  • Options are overridden for a file or a describe block.
  • Declaring the override keeps it visible rather than buried in a hook.
  • It applies to the whole scope, not to a single test.

test.extend

Defines custom fixtures, which is how page objects and seeded data are shared.

  • base.extend adds test-scoped and worker-scoped fixtures.
  • The value before use() is setup and everything after it is teardown.
  • A fixture no test requests is never created, so unused cost is zero.

Worker fixtures

{ scope: 'worker' } sets something up once per worker rather than per test.

  • { scope: 'worker' } creates the fixture once per worker process.
  • Teardown runs when the worker shuts down rather than after each test.
  • Every test in that worker shares it, so it must not hold per-test state.

Automatic fixtures

{ auto: true } applies a fixture without a test asking for it.

  • { auto: true } applies a fixture without any test requesting it.
  • It is how a policy is enforced across an entire suite.
  • It then runs for every test, including those that gain nothing from it.

test.beforeEach / afterEach

Per-test setup and teardown, with fixtures available in both.

  • Setup and teardown run around each test.
  • They run inside the test's own context, so nothing leaks onward.
  • Work here is paid once per test, not once per file.

test.beforeAll / afterAll

Per-worker setup, which runs again for each worker, not once globally.

  • Setup and teardown run once per worker for a file.
  • It suits a cost that genuinely can be shared.
  • State created here outlives the per-test contexts inside it.

test.step

Groups actions into a named step that appears in the report and the trace.

  • A named phase groups actions in the report and the trace.
  • Steps turn a long test into a readable narrative.
  • A failing step names the phase, which shortens diagnosis.

Setup projects

A project other projects depend on — where authentication runs once and saves storageState.

  • A project declared as a dependency runs before the projects that need it.
  • It is the documented way to authenticate once for the whole run.
  • Its failure stops dependent projects rather than letting them run unauthenticated.

globalSetup / globalTeardown

Runs once for the whole run, before any worker starts.

  • Code runs once for the entire test run.
  • It suits seeding a database or starting an external service.
  • It runs outside any worker, so test fixtures are unavailable.

storageState

Saves and restores cookies and local storage, so tests start already signed in.

  • Cookies and origin storage are saved to a file and reused by later contexts.
  • test.use({ storageState: { cookies: [], origins: [] } }) resets it for a signed-out test.
  • The official per-worker pattern keys the file by test.info().parallelIndex.

Network & mocking

page.route

Intercepts matching requests to fulfil, abort or modify them.

  • Matching requests are intercepted before they leave the browser.
  • Interception is what makes loading and failure states deterministic.
  • A route registered after navigation misses requests already sent.

route.fulfill

Responds from the test, with a body, status and headers of your choosing.

  • A response is supplied without contacting the server.
  • It is how an error or an empty state is produced on demand.
  • A fabricated shape that the real API never returns tests nothing.

route.abort

Blocks a request — how third-party scripts and images are kept out of a run.

  • A request is failed with a chosen error.
  • Aborting is how offline and blocked-resource behaviour is tested.
  • Aborting a required asset can break the page rather than the feature.

route.fetch / continue

Forwards the request, optionally with changes, and lets you edit the response.

  • A request is forwarded, optionally modified, and its response used.
  • It allows a real response to be inspected or patched.
  • Continuing with altered headers can break server-side validation.

page.routeFromHAR

Replays a recorded HAR file, so a whole session can be served offline.

  • Recorded traffic replays as the network layer.
  • A HAR is a realistic fixture captured from a real session.
  • It goes stale as the API changes, silently testing an old contract.

waitForResponse / waitForRequest

Waits for a specific network event, for flows with no visible signal.

  • Execution waits for a specific network event.
  • Waiting on the event ties the test to the cause rather than the clock.
  • The wait must be set up before the action that triggers it.

request fixture

A standalone API client sharing the browser's cookies — used to seed state without the UI.

  • HTTP calls are made outside the browser from the test.
  • It is how state is arranged without driving the interface.
  • It does not share the browser's cookies unless configured to.

APIRequestContext

Full HTTP testing on its own, so API and UI tests live in one suite.

  • A reusable API client carries its own base URL and headers.
  • It is the right tool for API-only tests.
  • Its storage state is separate from any browser context.

page.on('console')

Surfaces console messages, so a test can fail on an unexpected page error.

  • Console messages from the page are observed.
  • Failing on a console error catches problems no assertion looked for.
  • Third-party scripts produce noise that must be filtered.

Configuration

playwright.config.ts

Projects, reporters, timeouts, retries and the use defaults, all in one file.

  • Projects, reporters, timeouts and the web server live in one file.
  • One file is what makes the run reproducible outside a developer machine.
  • Per-project options override the top level, which is easy to miss.

projects

Named configurations — one per browser, viewport or setup dependency — run in one command.

  • Named configurations run the same tests differently.
  • Projects are what make browsers, devices and setup declarative.
  • Dependencies between projects control ordering.

webServer

Starts the application before the run and waits for it to answer.

  • The application is started before the suite and stopped after.
  • It removes the assumption that a server is already running.
  • Reusing an existing server locally can test a stale build.

baseURL

Lets tests navigate with relative paths, so the environment is a config change.

  • Relative paths resolve against a configured origin.
  • It is what lets the same suite run against any environment.
  • An absolute URL in a test ignores it entirely.

testMatch / testIgnore

Selects which files a project runs.

  • Which files are collected as tests is controlled.
  • It separates unit, integration and end-to-end runs in one repository.
  • An over-broad pattern collects helper files as empty suites.

fullyParallel

Runs tests inside a file in parallel too, not just across files.

  • Tests within a file run in parallel as well as across files.
  • It is the largest single throughput gain available.
  • Tests sharing mutable data start failing under it.

workers

How many parallel workers to use. CI usually wants fewer than a laptop.

  • The number of parallel worker processes is set.
  • Matching workers to cores is usually the right starting point.
  • More workers than the application can serve produces timeouts.

retries

Reruns a failed test. Useful in CI, and a flakiness detector rather than a fix.

  • A failing test is retried a set number of times.
  • Retries separate transient failures from real ones in the report.
  • Treating retries as a fix leaves the underlying race in place.

timeout / expect.timeout

The per-test and per-assertion budgets, tuned separately.

  • Per-test and per-assertion time limits are configured.
  • Separate limits let a slow assertion not raise the whole test budget.
  • Raising the global timeout hides which step is actually slow.

reporter

list, dot, html, json, junit, blob, or several at once.

  • Run output is formatted for humans or for CI.
  • Several reporters can run at once for both audiences.
  • A reporter that writes files needs its output preserved by CI.

Blob reports

Sharded runs emit blobs that merge-reports combines into one HTML report.

  • Shard results are emitted for later merging.
  • Merging is what produces one report from a sharded run.
  • Without merging, each shard reports only its own slice.

Debugging & tracing

trace: 'on-first-retry'

Records a trace only when a test retries, which is the setting most suites want.

  • Tracing records only when a test is retried.
  • It captures evidence exactly when something went wrong.
  • A test that fails without retries enabled produces no trace.

Trace Viewer

Replays a run with DOM snapshots, network, console and a timeline per action.

  • Actions, snapshots, network and console are replayed from a trace.
  • The DOM snapshot per step shows the page as the test saw it.
  • It only exists if tracing was enabled for that run.

--debug / PWDEBUG

Opens the Inspector, stepping through actions with live locator editing.

  • The run pauses with an inspector attached.
  • Stepping through beats reasoning about a failure from logs.
  • It disables timeouts, so behaviour differs from a normal run.

--ui

The UI mode: watch, time-travel and pick locators while tests run.

  • An interactive mode watches, filters and re-runs tests.
  • It is the fastest loop while writing tests.
  • It is a development tool and is not used in CI.

codegen

Records interactions into a script. A starting point, not a finished test.

  • Interactions in a browser are recorded as test code.
  • It is the quickest way to discover the right locators.
  • Generated code needs assertions and structure added by hand.

page.pause

Stops execution and opens the Inspector at that exact point.

  • Execution stops and hands control to the inspector.
  • Pausing at a chosen point beats stepping from the beginning.
  • A pause left in the code hangs the run in CI.

screenshot / video

Captures on failure, attached to the HTML report.

  • Images and recordings are captured during a run.
  • They are what make a CI-only failure explicable.
  • Capturing always is expensive, so it is usually on failure.

--last-failed

Reruns only what failed in the previous run.

  • Only the tests that failed previously are re-run.
  • It shortens the loop when fixing a handful of failures.
  • It depends on the previous run's results being present.

--repeat-each

Runs a test many times to prove whether it is genuinely flaky.

  • Each test runs several times in one invocation.
  • Repetition is how a suspected flake is confirmed.
  • A test passing ten times is not proof it cannot fail.

Advanced automation

Component testing

Mounts React, Vue or Svelte components in a real browser under the same runner.

  • A component mounts in a real browser and is asserted directly.
  • Real styles and layout apply, unlike a virtual renderer.
  • It bypasses routing and data loading, which stay untested here.

Visual comparisons

Baseline screenshots per project and platform, with --update-snapshots to accept changes.

  • Rendered output is diffed against approved images.
  • It catches regressions no functional assertion describes.
  • Fonts and rendering differ per platform, which produces false diffs.

Accessibility scanning

@axe-core/playwright runs an audit inside an existing test.

  • Automated accessibility checks run against a page.
  • It catches a real subset of issues very cheaply.
  • Most accessibility problems are not machine-detectable.

Emulation

Device descriptors, locale, timezone, colour scheme, reduced motion and geolocation.

  • Viewport, device, locale, timezone and colour scheme are simulated.
  • Emulation is what tests responsive and localised behaviour.
  • It emulates the environment, not the device's real performance.

Permissions

Grants or denies camera, clipboard, notifications and geolocation per context.

  • Browser permissions are granted or denied for a context.
  • Granting up front avoids a dialog the test cannot click.
  • Permissions are per context, so a new context resets them.

Clock API

Controls the page's clock so timers, polling and expiry can be tested deterministically.

  • Time is controlled so timers and dates are deterministic.
  • Controlling time is what makes a timeout testable in milliseconds.
  • Installing it affects every timer, including the framework's own.

Sharding

--shard=1/4 splits a suite across CI machines, merged afterwards into one report.

  • A suite is split across machines by index.
  • Sharding is how a long suite fits a CI time budget.
  • Shards divide by count, so slow tests can land unevenly.

Authentication reuse

Signing in once in a setup project and reusing the state is the single biggest speed win.

  • Signing in once and reusing the saved state removes the slowest step from every test.
  • The docs authenticate in a clean context by passing storageState: undefined.
  • Waiting for the final URL matters, because a login can set cookies across redirects.

Page object model

Encapsulates locators and flows in classes, exposed to tests as fixtures.

  • Locators and actions for a screen are grouped in a class.
  • It keeps a selector change confined to one file.
  • Over-abstracting hides what a test actually does.

Docker image

The official image ships the browsers and system dependencies, so CI matches local runs.

  • An official image carries the browsers and their dependencies.
  • It is what makes local and CI runs match.
  • The image version must track the library version.

playwright install

Downloads browser binaries; --with-deps also installs the OS packages they need.

  • Browser binaries are downloaded separately from the npm package.
  • Keeping them out of the package is why the install step exists at all.
  • The --with-deps flag also installs the system libraries a CI image lacks.

Ask follow-up questions on any topic in your dashboard.

Start learning