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

Technology handbook

Playwright Automation — Browser Testing & Debugging

Reliable browser automation with locators, auto-waiting, projects, fixtures and trace debugging.

Topics
31
Sections
10

Learning module

Playwright learning module

Playwright Test is an end-to-end test framework for modern web apps that bundles a test runner, assertions, isolation, parallelization and rich tooling, and runs on Chromium, WebKit and Firefox across Windows, Linux and macOS.

  • Each test gets a fresh browser context: isolated and cheap.
  • Actions auto-wait; web-first assertions retry; remove sleeps.
  • Prefer getByRole and other user-facing locators.
  • Use trace: "on-first-retry" so CI failures come with a full replay.

Flaky, slow end-to-end tests nobody trusts: Without Playwright, teams write E2E tests full of sleeps and retries, share one browser session so tests depend on each other, test only in Chrome, and debug CI failures from a single screenshot. The suite becomes slow and flaky, so it gets ignored. Playwright's actionability checks and retrying assertions remove timing guesswork, per-test contexts make tests independent and parallel, one API covers Chromium, Firefox and WebKit, and traces show the DOM, network and console at every step of a failed run.

Browser basics

Locators

Find elements by accessible role, label and text so tests follow the user-facing contract.

  • An element is found by accessible role, label and text rather than by markup.
  • Querying the way a user perceives the page keeps the test honest about the contract.
  • A locator is lazy: it resolves when it is used, not when it is declared.

Auto-waiting

Let Playwright wait for actionable, stable elements instead of adding arbitrary sleeps.

  • Playwright waits for an element to be actionable before acting on it.
  • Actionable means attached, visible, stable and able to receive the event.
  • An arbitrary sleep is both slower than needed and still sometimes too short.

Browser contexts

Isolate cookies, storage and permissions with a fresh context for each scenario.

  • Cookies, storage and permissions are isolated in a fresh context per scenario.
  • A context is cheap, which is why isolation does not cost a browser launch.
  • State leaks between tests only when a context is deliberately shared.

Pages and popups

Coordinate tabs, popup windows and page lifecycle events without race conditions.

  • Tabs, popups and page lifecycle are coordinated without races.
  • The popup must be awaited before the action that opens it completes.
  • A page opened and never closed keeps its context alive.

Network interception

Route, fulfill or observe requests to test deterministic loading and failure states.

  • Requests are routed, fulfilled or observed to test loading and failure states.
  • Fulfilling a route is how an error path is tested without breaking a server.
  • A route registered after navigation misses the requests already made.

Downloads and uploads

Drive file chooser and download flows while asserting the resulting files.

  • File chooser and download flows are driven and their results asserted.
  • The download event must be awaited before the click that triggers it resolves.
  • A downloaded file lives in a temporary path until it is deliberately saved.

Test design

Assertions

Use web-first assertions that retry until the expected browser state is observable.

  • Web-first assertions retry until the expected state is observable.
  • Retrying is what removes the race between the assertion and the render.
  • Asserting on a value read once cannot retry, because the value is already fixed.

Fixtures

Share setup and teardown through typed fixtures without hiding test dependencies.

  • Setup and teardown are shared through typed fixtures.
  • A test declares the fixtures it uses, so its dependencies stay visible.
  • A fixture is only constructed for tests that ask for it.

Visual comparisons

Lock important visual regions with controlled screenshots and reviewable diffs.

  • Important regions are locked with controlled screenshots and reviewable diffs.
  • Masking volatile areas is what stops a clock failing every run.
  • Baselines are platform-specific, so a local image rarely matches CI.

Configuration

Projects and browsers

Run the same suite across browsers, devices, environments and authentication states.

  • The same suite runs across browsers, devices, environments and sign-in states.
  • A project is a named configuration, which is what makes a matrix declarative.
  • Projects can depend on each other, which is how setup runs first.

Playwright Test configuration

Set projects, reporters, timeouts, web servers and device profiles in one config.

  • Projects, reporters, timeouts, web servers and devices are set in one file.
  • The web server entry is what makes the suite start its own application.
  • Per-project options override the top level, which is easy to overlook.

Debugging

Tracing and debugging

Capture trace, screenshot, video and network evidence for a failed test.

  • Trace, screenshot, video and network evidence are captured for a failure.
  • Evidence collected on the failing run is what makes a CI-only failure diagnosable.
  • Capturing everything on every run is expensive, so it is usually on-failure.

Trace viewer

Replay actions, DOM snapshots, network calls and console output from a failed run.

  • Actions, DOM snapshots, network calls and console output are replayed.
  • The DOM snapshot at each step is what shows the page as the test saw it.
  • A trace is only available if tracing was enabled for that run.

Assertions

Web-first assertions

Assert on visible, enabled and attached state with retryable expectations.

  • Visible, enabled and attached state are asserted with retrying expectations.
  • Each has its own timeout, so a slow case need not raise the global one.
  • Negating an assertion changes what is waited for, not merely the result.

Locators

Role and text locators

Prefer accessible roles, labels and test IDs over brittle CSS or XPath selectors.

  • Accessible roles, labels and test IDs are preferred over CSS or XPath.
  • A CSS selector breaks on a restyle that changed nothing a user sees.
  • If a role locator cannot find it, assistive technology probably cannot either.

Locator filtering

Narrow repeated components by text, descendant state or a related locator.

  • A repeated component is narrowed by text, descendant state or a related locator.
  • Filtering composes, so a row is found by what it contains rather than by index.
  • An index-based match reorders the moment the list does.

Fixtures

Authentication state

Reuse a securely prepared storage state while keeping tests isolated from one another.

  • A prepared storage state is reused while tests stay isolated.
  • Reusing it removes a sign-in from every test without sharing a session.
  • A stored state expires, so it must be refreshed rather than committed forever.

Test hooks

Use beforeEach, afterEach and fixture composition for predictable setup and cleanup.

  • beforeEach, afterEach and fixture composition give predictable setup and cleanup.
  • Hooks run in declaration order, which is what makes nesting predictable.
  • A failure inside a hook fails the test rather than skipping it silently.

Projects and browsers

Parallel workers

Scale independent tests across workers while controlling shared resources and data.

  • Independent tests scale across workers with shared resources controlled.
  • Each worker is a separate process, so module state is not shared.
  • Two workers writing the same fixture row is the usual source of flake.

Retries and sharding

Separate transient evidence from real failures and distribute large suites across CI jobs.

  • Transient evidence is separated from real failures and suites split across CI jobs.
  • A test that passes only on retry is reporting a race, not a fixed problem.
  • Sharding divides by count, so slow tests can land unevenly.

Test hooks

test.beforeEach

Arrange per-test state, with the page fixture already created for that test.

  • Per-test state is arranged with the page fixture already created.
  • It runs inside the test's own context, so nothing leaks to the next test.
  • Expensive work here is paid once per test rather than once per file.

test.afterEach

Undo what the test created, and attach diagnostics from the test's own result.

  • What the test created is undone, and diagnostics attached from its result.
  • The test result is available here, so evidence can be attached only on failure.
  • It still runs when the test failed, which is exactly when cleanup matters.

test.beforeAll and afterAll

Share worker-level setup, remembering it outlives the isolated contexts inside it.

  • Worker-level setup is shared across the tests in a file.
  • It outlives the per-test contexts, so state created here is shared.
  • A page created here belongs to no test and appears in no trace.

Hook scope in describe blocks

A hook declared inside describe applies to that group only, in declaration order.

  • A hook inside describe applies only to that group, in declaration order.
  • Scoping is what lets one file hold groups with different setup.
  • An outer hook still runs first, so the two compose rather than replace.

Automatic fixtures over hooks

An auto fixture carries its own teardown, so setup travels with the thing it provides.

  • An auto fixture carries its own teardown alongside its setup.
  • Setup travelling with the thing it provides is what stops cleanup drifting apart.
  • It applies without being requested, which is the cost of the convenience.

test.step

Name a phase of a long test so the trace and the report read as steps rather than one block.

  • A phase of a long test is named so the trace reads as steps.
  • Named steps turn a wall of actions into a readable narrative.
  • A failing step names the phase, which shortens the diagnosis.

globalSetup and globalTeardown

Run once per test run: seed a database, start a service, then tear it down.

  • Work runs once per test run, such as seeding a database or starting a service.
  • It runs outside any worker, so it cannot use test fixtures.
  • State it creates is shared by every worker, which makes it a contention point.

Authentication in a setup project

Sign in once in a setup project and reuse storageState instead of a beforeEach per test.

  • Signing in happens once in a setup project and storage state is reused.
  • A project dependency is what guarantees it runs before the tests that need it.
  • A per-test sign-in repeats the slowest part of the suite every time.

test.use for overrides

Change options for a file or a describe block rather than reconfiguring inside a hook.

  • Options are changed 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 one test inside it.

test.fail and test.fixme

Mark expected failures declaratively instead of branching inside a hook.

  • Expected failures are marked declaratively rather than branched around.
  • A marked failure that starts passing is reported, which a skip would hide.
  • fixme does not run the test at all; fail runs it and expects it to fail.

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

Start learning