Playwright logoPlaywright INTERMEDIATE

Playwright

Complete reference for Playwright — the cross-browser end-to-end testing framework by Microsoft for reliable web automation

10 min read
playwrighttestinge2eend-to-endautomationbrowserchromiumfirefoxwebkitcross-browser

Installation & Setup

Installing Playwright and creating your first project

Create New Project

Initialize a new Playwright test project with all dependencies

bash
💡 The init command scaffolds config, example tests, and GitHub Actions workflow
⚡ Use --with-deps on CI to install system-level browser dependencies automatically
📌 Playwright bundles its own browsers — no need for separate Chrome/Firefox installs
🟢 Supports Chromium, Firefox, and WebKit out of the box
installsetup

Configuration File

Set up playwright.config.ts with projects, reporters, and options

typescript
💡 The webServer option auto-starts your dev server before running tests
⚡ Use fullyParallel: true to run tests in parallel across files and within files
📌 forbidOnly prevents accidental test.only commits from passing in CI
🟢 Device emulation is built-in — just spread from the devices object
configsetup

Writing Tests

Test structure, hooks, and organizing test suites

Basic Test Structure

Write tests with test blocks, navigation, and assertions

typescript
💡 Each test gets a fresh browser context — no state leaks between tests
⚡ Playwright auto-waits for elements before interacting — no manual waits needed
📌 Use test.skip() with a condition to skip tests based on platform or environment
🟢 The page fixture is the most common — it provides a fresh page for each test
teststructure

Test Hooks & Grouping

Organize tests with describe blocks and lifecycle hooks

typescript
💡 beforeEach/afterEach run for every test — use for navigation and cleanup
⚡ beforeAll/afterAll run once per describe block — ideal for database seeding
📌 Use describe.configure({ mode: "serial" }) when tests depend on each other
🟢 Describe blocks can be nested for better organization of large test suites
hooksdescribeorganize

Locators

Finding elements on the page with built-in locator strategies

Built-in Locators

Use role-based, text, and semantic locators to find elements

typescript
💡 Prefer getByRole over CSS selectors — it mirrors how users and assistive tech see the page
⚡ Locators auto-wait and auto-retry — no need for explicit waitFor calls
📌 Use filter() to narrow down results from broad locators like getByRole("listitem")
🟢 getByTestId uses data-testid by default — customizable in playwright.config.ts
locatorsselectors

Actions & Interactions

Clicking, typing, selecting, and interacting with page elements

Common Actions

Click, type, select, check, and interact with elements

typescript
💡 fill() clears the input before typing — use pressSequentially() for char-by-char input
⚡ All actions auto-wait for the element to be visible and enabled before acting
📌 Use setInputFiles([]) to clear a file upload, and pass arrays for multiple files
🟢 Keyboard shortcuts work with page.keyboard.press() using modifier+key syntax
actionsclicktypefill

Assertions

Web-first assertions that auto-wait and auto-retry

Page & Element Assertions

Assert on page state, element visibility, text content, and attributes

typescript
💡 All expect assertions auto-retry until the condition is met or timeout expires
⚡ Use soft assertions when you want to collect all failures without stopping the test
📌 Screenshot assertions auto-generate golden files on first run — commit them to git
🟢 Default assertion timeout is 5s — override per-assertion with { timeout: ms }
assertionsexpect

Emulation & Devices

Emulate mobile devices, viewports, geolocation, locale, and color schemes

Device & Viewport Emulation

Test on mobile devices, custom viewports, and different screen configurations

typescript
💡 Playwright ships with 100+ device profiles — use devices["Device Name"] to emulate any of them
⚡ Device profiles include viewport, userAgent, deviceScaleFactor, isMobile, and hasTouch
📌 Use page.setViewportSize() mid-test to verify responsive breakpoints dynamically
🟢 Each project runs your entire test suite — great for cross-device coverage in CI
emulationdevicesviewportmobile

Locale, Timezone & Geolocation

Emulate user locale, timezone, geolocation, permissions, and color scheme

typescript
💡 test.use() overrides config-level settings for all tests in the current file
⚡ emulateMedia() lets you switch color scheme mid-test without reloading
📌 permissions must be granted explicitly — geolocation, notifications, clipboard, etc.
🟢 Locale affects Intl APIs, date formatting, and number display in the browser context
localetimezonegeolocationdark-mode

Visual & Snapshot Testing

Compare screenshots and snapshots against golden baselines

Screenshot Comparisons

Capture and compare page or element screenshots against baselines

typescript
💡 Golden files auto-generate on first run — commit them to git for CI comparisons
⚡ Use mask to hide dynamic content like timestamps or avatars that change between runs
📌 Run npx playwright test --update-snapshots to regenerate baselines after intentional changes
🟢 Screenshots are browser-specific — each project gets its own snapshot folder
screenshotvisualsnapshotcomparison

Parallelism & Sharding

Run tests in parallel across workers and shard across CI machines

Parallel Execution & Sharding

Configure parallel workers and split test suites across CI machines

typescript
💡 fullyParallel: true runs tests within a single file in parallel — not just across files
⚡ Sharding splits the full test suite across CI machines — combine with GitHub Actions matrix
📌 Use describe.configure({ mode: "serial" }) when tests in a block depend on each other
🟢 Default worker count is half your CPU cores — set workers: 1 on CI to reduce flakiness
parallelshardingworkersci

Retries & Timeouts

Configure test retries for flaky tests and set timeout boundaries

Configuring Retries

Automatically retry failed tests to handle flaky behavior

typescript
💡 Retries re-run the entire test including beforeEach hooks — each retry gets a clean state
⚡ Traces with "on-first-retry" only record when a test fails and retries — saving disk space
📌 Use testInfo.retry to detect retries and add conditional cleanup or logging
🟢 Set retries: 0 locally for fast feedback, retries: 2 on CI for stability
retriesflaky

Timeout Configuration

Set timeouts for tests, actions, navigation, and assertions

typescript
💡 test.slow() triples the timeout — use for known slow tests instead of hardcoding a number
⚡ The 4 timeout layers: test > action > navigation > expect — each independently configurable
📌 Per-assertion timeout overrides expect.timeout — useful for elements that load asynchronously
🟢 Default test timeout is 30s — increase for E2E flows, decrease for unit-style tests
timeoutslowconfiguration

Navigation & Waiting

Page navigation, waiting strategies, and auto-wait behavior

Navigation

Navigate between pages and wait for load states

typescript
💡 Playwright auto-waits for navigation to complete — manual waits are rarely needed
⚡ Use waitForResponse to synchronize on API calls triggered by user actions
📌 Avoid waitForTimeout (sleep) — prefer waiting on specific conditions like URL or element state
🟢 waitUntil: "networkidle" waits for no network requests for 500ms — useful for SPAs
navigationwaitgoto

Network Mocking & Interception

Intercept, mock, and modify network requests and responses

Mock API Responses

Intercept API calls and return custom data without hitting the server

typescript
💡 Use route.fulfill({ json }) as a shorthand — Playwright sets content-type automatically
⚡ route.fetch() lets you intercept the real response and modify it before returning
📌 Route patterns use glob syntax — ** matches any path segment, * matches within a segment
🟢 Mock routes before page.goto() to ensure requests are intercepted from the start
mocknetworkrouteapi

API Testing

Test REST APIs directly without browser UI using the request fixture

API Requests

Send HTTP requests directly to test your API endpoints

typescript
💡 The request fixture uses baseURL from config — no need for full URLs
⚡ Combine API calls with UI testing to set up state quickly without clicking through forms
📌 The request fixture shares cookies/auth state with the browser context
🟢 Use API testing for fast backend validation without the overhead of browser rendering
apirequesthttp

Fixtures & Page Object Model

Custom fixtures for reusable setup and the Page Object pattern

Custom Fixtures

Create reusable test fixtures for shared setup logic

typescript
💡 Page Objects encapsulate page interactions — tests read like user stories
⚡ Custom fixtures handle setup and teardown automatically for every test that uses them
📌 Export your extended test and expect from a shared file so all tests use the same fixtures
🟢 The use() callback marks where the test runs — code after it is teardown logic
fixturespage-objectpom

Authentication & Storage State

Reuse authentication state across tests for faster execution

Reuse Auth State

Log in once and share the session across multiple tests

typescript
💡 storageState saves cookies and localStorage — tests start already logged in
⚡ The setup project runs once, then all dependent projects reuse the saved auth state
📌 Add playwright/.auth/ to .gitignore — auth state files contain session tokens
🟢 Use dependencies in config to ensure setup runs before authenticated test projects
authloginstorage-state

Debugging & Trace Viewer

Debug failing tests with UI mode, trace viewer, and screenshots

Debugging Tools

Use UI mode, trace viewer, and headed mode to debug tests

bash
💡 UI mode is the best debugging experience — shows DOM snapshots at every step
⚡ Use page.pause() in your test code to open the Inspector at a specific point
📌 Traces capture screenshots, DOM snapshots, network, and console logs for every action
🟢 Upload trace.zip to trace.playwright.dev to share with teammates — no install needed
debugtraceui-mode

Running Tests & CI

Run tests locally and in continuous integration pipelines

CLI Commands

Common commands for running and filtering tests

bash
💡 Use codegen to record browser interactions and generate test code automatically
⚡ --workers=1 forces serial execution — useful for debugging flaky tests
📌 Use --update-snapshots after intentional UI changes to refresh golden screenshots
🟢 Combine --grep with --project to run specific tests in specific browsers
clirunci

GitHub Actions CI

Run Playwright tests in a GitHub Actions workflow

yaml
💡 --with-deps installs system libraries needed by browsers on the CI runner
⚡ Upload the HTML report as an artifact to debug failures without re-running
📌 Use if: ${{ !cancelled() }} so the report uploads even when tests fail
🟢 The init command generates this workflow automatically — customize as needed
cigithub-actionsworkflow