Playwright is one of the strongest choices for modern end-to-end testing because it combines browser automation, reliable waiting behavior, cross-browser support, and a clean developer experience. This Playwright cheat sheet is built for speed: scan the syntax, copy the patterns, and use the examples as a reference while you build or maintain tests.

What this Playwright cheat sheet covers

This page focuses on the Playwright fundamentals that teams use most often:

  • installation and setup
  • running tests from the CLI
  • locators and selectors
  • common actions
  • assertions
  • waiting and synchronization
  • fixtures
  • mocking and network control
  • authentication
  • debugging and trace-based investigation
  • code generation
  • best practices
  • common mistakes

Playwright at a glance

Playwright is a browser automation and testing framework used for end-to-end testing, UI testing, and broader web testing workflows. Playwright is positioned around reliable browser automation, with strong support for locators, assertions, multiple browsers, test isolation, and debugging tools.

Use caseWhy Playwright fits
End-to-end testingCovers full user journeys across browsers
UI automationInteracts with modern front-end apps reliably
Regression testingGood for repeatable browser checks
Cross-browser validationSupports Chromium, Firefox, and WebKit
Authenticated flowsHandles reusable session state
API + UI testingWorks across both browser and network layers

Core Playwright commands

Quick Command Recap

TaskCommand
Install Playwrightnpm init playwright@latest
Run all testsnpx playwright test
Run one filenpx playwright test tests/example.spec.ts
Run in headed modenpx playwright test --headed
Run in UI modenpx playwright test --ui
Debug testsnpx playwright test --debug
Run last failed testsnpx playwright test --last-failed
Show HTML reportnpx playwright show-report
Generate starter codenpx playwright codegen https://example.com

First Playwright test

A typical Playwright setup starts with installing the package, initializing the project, and then writing your first test file.

import { test, expect } from '@playwright/test';

test('homepage has title', async ({ page }) => {
  await page.goto('https://example.com');
  await expect(page).toHaveTitle(/Example/);
});

Setup and configuration

Typical config ideas

A Playwright config usually handles:

  • browser projects
  • base URL
  • retries
  • trace collection
  • test timeout
  • parallel execution
  • screenshots and videos on failure

Example config snippet

import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    baseURL: 'https://example.com',
    trace: 'on-first-retry',
  },
});

Running Tests

The Playwright CLI is built for flexibility. You can run all tests, a single test file, a subset of tests, a specific browser project, or only the tests that failed last time. The docs also document --debug for Inspector-based debugging.

Common commands

npx playwright test
npx playwright test landing-page.spec.ts
npx playwright test tests/todo-page/
npx playwright test landing login
npx playwright test --last-failed

Run on a specific browser project

npx playwright test --project webkit
npx playwright test --project firefox

Debug mode

npx playwright test --debug

Run one test at a specific line

npx playwright test example.spec.ts:10 --debug

Playwright tests run in parallel by default, and projects let you target multiple browsers or device profiles from the same suite.

Locators cheat sheet

Locators are one of the most important concepts in Playwright. Playwright works best when you target the page the way a user would. That means preferring visible roles, labels, and text before falling back to CSS selectors.

LocatorExampleBest for
getByRole()page.getByRole('button', { name: 'Sign in' })Buttons, links, menus, form controls
getByLabel()page.getByLabel('Email')Form fields
getByText()page.getByText('Continue')Visible text
getByPlaceholder()page.getByPlaceholder('Search')Inputs with placeholders
getByAltText()page.getByAltText('Logo')Images
getByTitle()page.getByTitle('Help')Tooltips and titles
getByTestId()page.getByTestId('submit-btn')Stable custom hooks
locator()page.locator('.card')CSS targeting
frameLocator()page.frameLocator('iframe')Embedded frames

Locator examples

await page.getByRole('button', { name: 'Save' }).click();
await page.getByLabel('Password').fill('secret');
await page.getByText('Continue').click();

Common actions

Once an element is located, Playwright makes common user interactions straightforward. These actions are most reliable when combined with resilient locators rather than CSS paths or arbitrary timeouts.

ActionExample
Clickawait page.getByRole('button', { name: 'Save' }).click();
Fill inputawait page.getByLabel('Email').fill('me@example.com');
Typeawait page.getByLabel('Search').type('playwright');
Select optionawait page.getByLabel('Country').selectOption('IN');
Check checkboxawait page.getByLabel('Subscribe').check();
Uncheck checkboxawait page.getByLabel('Subscribe').uncheck();
Upload fileawait page.getByLabel('Upload').setInputFiles('file.pdf');
Hoverawait page.getByText('Menu').hover();
Press a keyawait page.keyboard.press('Enter');
Double clickawait page.getByText('Item').dblclick();

Action pattern

await page.getByRole('button', { name: 'Submit' }).click();
await page.getByLabel('Email').fill('me@example.com');
await page.getByRole('button', { name: 'Submit' }).click();

Assertions cheat sheet

Assertions are one of the reasons Playwright feels stable. Assertions are written with expect, and emphasize async matchers that wait for the expected condition. This is a key reason Playwright tests are less flaky than tests that rely on manual sleeps.

AssertionExampleUse case
toBeVisible()await expect(page.getByText('Success')).toBeVisible();Element should appear
toBeHidden()await expect(page.getByText('Loading')).toBeHidden();Element should disappear
toHaveText()await expect(page.getByTestId('status')).toHaveText('Done');Exact text match
toContainText()await expect(page.locator('h1')).toContainText('Dashboard');Partial text match
toHaveCount()await expect(page.locator('li')).toHaveCount(3);Element count
toHaveURL()await expect(page).toHaveURL(/dashboard/);Navigation check
toHaveTitle()await expect(page).toHaveTitle(/Home/);Page title
toBeEnabled()await expect(button).toBeEnabled();Clickable state
toBeDisabled()await expect(button).toBeDisabled();Disabled state
toHaveValue()await expect(input).toHaveValue('john');Input value

Assertion example

await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
await expect(page).toHaveURL(/dashboard/);

The docs recommend web-first assertions because they automatically wait for the page to reach the expected state. That makes them a better default than ad hoc polling or manual delays.

Waiting and synchronization

Playwright is designed to wait intelligently. In most cases, you should wait for a visible outcome rather than hard-coding time. Playwright’s auto-waiting covers many common cases, so the default approach should be to rely on locators and assertions rather than fixed pauses.

PreferAvoid
await expect(locator).toBeVisible()await page.waitForTimeout(5000)
await expect(page).toHaveURL(...)Manual polling
await locator.click()Clicking before the element is ready
await expect(page.getByText('Saved')).toBeVisible()Sleeping and hoping

Better pattern

await page.getByRole('button', { name: 'Submit' }).click();
await expect(page.getByText('Submitted')).toBeVisible();

Use explicit waits only when you truly need them, and prefer waiting for a visible application state instead of waiting for a duration. That keeps the suite faster and more deterministic.

Navigation and page handling are at the core of most Playwright tests. Whether you are validating a simple redirect, handling multi-step workflows, or working with tabs and popups, Playwright provides built-in methods to control navigation reliably without introducing flakiness.

Common page actions

await page.goto('https://example.com');
await page.reload();
await page.goBack();
await page.goForward();

Tabs and windows

const newPage = await context.newPage();
await newPage.goto('https://example.com');

Screenshots

await page.screenshot({ path: 'homepage.png', fullPage: true });

Understanding how to move between pages, manage browser contexts, and capture page state ensures your tests remain stable while accurately reflecting real user journeys.

Fixtures cheat sheet

Fixtures make tests cleaner and more isolated. Fixtures are a way to give each test exactly what it needs while keeping test environments isolated. This helps prevent cascading failures and makes suites easier to organize.

Why fixtures matter

  • simplify browser/context lifecycle management
  • isolate state between tests
  • reduce duplicate setup
  • group tests by meaning, not just shared code
FixturePurpose
pageNew page for the test
contextIsolated browser context
browserLaunch browser instances
Custom fixturesShare reusable setup logic

Example

import { test, expect } from '@playwright/test';

test('user can open dashboard', async ({ page }) => {
  await page.goto('/dashboard');
  await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
});

Playwright’s fixture model is especially useful when you need reusable setup such as authenticated contexts, seeded data, or API state.

Mocking and network control

Playwright can intercept, modify, and mock HTTP and HTTPS traffic, including XHR and fetch requests. Playwright also provides support for mocking with HAR files, which is useful when you need deterministic tests without calling live services.

Typical uses

  • simulate a slow backend
  • return controlled API responses
  • isolate frontend behavior from unstable integrations
  • replay network traffic from HAR
TaskExample
Mock API responsepage.route()
Block requestroute.abort()
Modify responseroute.fulfill()
Replay trafficHAR-based mocking

Example: mock an API response

await page.route('**/api/users', async route => {
  await route.fulfill({
    status: 200,
    contentType: 'application/json',
    body: JSON.stringify([{ id: 1, name: 'Asha' }]),
  });
});

Mocking is especially valuable in regression suites where you want consistent results independent of backend volatility.

Authentication cheat sheet

Playwright supports authenticated state reuse through browser contexts, which helps avoid logging in for every single test. Browser contexts are isolated, and existing authenticated state can be loaded to speed up tests and reduce repeated setup.

PatternUse when
Login once and reuse stateYou want faster suites
Save storage stateYou need persistent auth
Separate auth setupYou want cleaner structure

Example

test.use({ storageState: 'auth.json' });

This is useful for admin dashboards, role-based applications, and any suite where authentication is expensive or rate-limited.

Debugging cheat sheet

Debugging is a major Playwright strength. The docs recommend UI mode, Inspector debugging, and Trace Viewer to understand failures. Trace Viewer lets you step through a recorded test and inspect actions, snapshots, and network activity after the run.

ToolBest for
--debugStep-by-step debugging
UI modeInteractive test execution
Trace ViewerReviewing what happened after a failure
ScreenshotsVisual checkpoints
VideoCapturing the full run

Debug commands

npx playwright test --debug
npx playwright test --ui
npx playwright show-report

Playwright Trace Viewer acts as a GUI that helps you explore recorded traces after the script finishes, which is especially useful for CI failures.

Code generation cheat sheet

Playwright’s test generator, or codegen, can record interactions and generate test code while you browse. It prioritizes role, text, and test id locators, and improves locators when multiple elements match so the resulting test is more resilient.

CommandPurpose
npx playwright codegen https://example.comRecord interactions and generate code
npx playwright codegen --target=typescript https://example.comGenerate TypeScript output
npx playwright codegen --device="iPhone 13" https://example.comRecord against a device profile

Why it is useful

  • bootstrap a new test quickly
  • discover good locator patterns
  • reduce manual setup time
  • get a starting point for exploratory test creation

Code generation is not the final answer for every test, but it is a strong accelerator when you need to build coverage fast.

Best practices

DoDon’t
Use role/label/text locatorsStart with brittle CSS chains
Prefer assertions over sleepsRely on waitForTimeout()
Keep tests isolatedShare mutable state between tests
Mock unstable dependenciesDepend on flaky live services
Use traces for failuresGuess at the root cause
Reuse auth stateLog in manually in every test

Common mistakes to avoid

1. Fragile selectors

Bad:

page.locator('div > div > div:nth-child(2) > button')

Better:

page.getByRole('button', { name: 'Save' })

2. Fixed delays

Bad:

await page.waitForTimeout(3000);

Better:

await expect(page.getByText('Saved')).toBeVisible();

3. Overcomplicated tests

Keep one test focused on one behavior. Long tests that do too much are harder to debug and maintain.

4. Testing implementation instead of behavior

Test what the user sees and does. Avoid coupling tests to internal structure unless there is no better option.

A good Playwright test suite is not defined by how many tests you write, but by how reliably those tests reflect real user behavior. The patterns in this cheat sheet are what separate stable, scalable test suites from brittle ones. As your application grows, these fundamentals help reduce flakiness, speed up execution, and make failures easier to debug and trust.

Use this Playwright cheat sheet as a working reference, not just a one-time read. Whether you are writing new tests, debugging failures, or improving an existing suite, the goal is consistency and clarity. Over time, applying these practices will help your team move faster with confidence, ship fewer regressions, and build a testing workflow that scales alongside your product.

FAQ’s

 

Q: What is Playwright used for?

A: Playwright is used for browser automation, end-to-end testing, UI testing, and cross-browser validation. It is particularly effective for modern web applications that require reliable, repeatable interaction testing across multiple browsers.

 

Q: Is Playwright better than Selenium?

A: For many modern test suites, Playwright is easier to use due to its built-in waiting mechanisms, powerful debugging tools, and more streamlined developer experience. However, the choice depends on existing infrastructure and team familiarity.

 

Q: What is the best locator strategy in Playwright?

A: The recommended approach is to use user-facing locators such as getByRole and getByLabel. These are more resilient and maintainable compared to CSS selectors or deeply nested DOM paths.

 

Q: How do I run tests in headed mode?

A: You can run Playwright tests in headed mode using the following command:

npx playwright test --headed

 

Q: How do I debug a failing Playwright test?

A: Use Playwright’s debugging tools such as debug mode, UI mode, screenshots, and trace reports. These allow you to step through test execution and identify failures precisely.

 

Q: Can Playwright mock APIs?

A: Yes. Playwright allows you to intercept network requests, modify responses, abort calls, and even replay traffic using HAR files, making it effective for isolating frontend behavior.

 

Q: Does Playwright support authenticated testing?

A: Yes. You can persist authentication state using storage snapshots, allowing tests to bypass repeated login flows and improve execution speed.

 

Q: How do I keep Playwright tests stable?

A: Use resilient locators, rely on built-in assertions that auto-wait, isolate test state with fixtures, and mock unstable external dependencies to reduce flakiness.

 

Q: Is Playwright good for regression testing?

A: Yes. Playwright is well suited for regression testing due to its stable automation engine, support for parallel execution, strong debugging capabilities, and reusable test architecture.

 

Q: Should I use waitForTimeout() in Playwright?

A: Only in rare cases. It is better to wait for actual UI states or use assertions that automatically retry, as fixed delays can lead to flaky and slow tests.

 

Q: How do I generate tests faster in Playwright?

A: Use Playwright’s codegen feature to record interactions and generate a baseline test. Afterward, refine locators and assertions to make the test more stable and maintainable.