Playwright Test Recorder Guide
Master Playwright's codegen command, write resilient selectors, handle authentication state, and ship reliable end-to-end tests to CI.
Recording Your First Test
Playwright's codegen command opens a browser and records every interaction as runnable test code in real time.
# Install Playwright (first time) npm init playwright@latest # Record against your local dev server npx playwright codegen http://localhost:3000 # Record with Firefox npx playwright codegen --browser firefox https://example.com # Record and save authentication state (cookies, localStorage) npx playwright codegen --save-storage=auth.json https://example.com/login
Selector Priority — Most to Least Resilient
| Selector | Example | Resilience |
|---|---|---|
| getByRole | getByRole('button', { name: 'Submit' }) | Excellent |
| getByLabel | getByLabel('Email address') | Excellent |
| getByPlaceholder | getByPlaceholder('Search...') | Good |
| getByText | getByText('Sign in') | Good |
| getByTestId | getByTestId('submit-btn') | Good (needs markup) |
| CSS selector | locator('.btn-primary') | Fragile |
| XPath | locator('//button[1]') | Very fragile |
Complete Test with Auto-Waiting
// tests/login.spec.ts
import { test, expect } from '@playwright/test';
test.describe('Login flow', () => {
test('successful login redirects to dashboard', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('[email protected]');
await page.getByLabel('Password').fill('secret123');
await page.getByRole('button', { name: 'Sign in' }).click();
// Auto-wait for navigation — no sleeps needed
await page.waitForURL('/dashboard');
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
});
test('invalid credentials shows error', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('[email protected]');
await page.getByLabel('Password').fill('wrongpass');
await page.getByRole('button', { name: 'Sign in' }).click();
await expect(page.getByText('Invalid credentials')).toBeVisible();
await expect(page).toHaveURL('/login');
});
}); Authentication State Reuse
// global-setup.ts — logs in once, saves session
import { chromium } from '@playwright/test';
export default async function globalSetup() {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('/login');
await page.getByLabel('Email').fill(process.env.TEST_USER!);
await page.getByLabel('Password').fill(process.env.TEST_PASS!);
await page.getByRole('button', { name: 'Sign in' }).click();
await page.waitForURL('/dashboard');
await page.context().storageState({ path: 'playwright/.auth/user.json' });
await browser.close();
}
// playwright.config.ts
export default defineConfig({
globalSetup: './global-setup.ts',
projects: [
{ name: 'authenticated', use: { storageState: 'playwright/.auth/user.json' } },
],
}); GitHub Actions CI Setup
# .github/workflows/playwright.yml
name: Playwright E2E Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test --workers=4
env:
TEST_USER: ${{ secrets.TEST_USER }}
TEST_PASS: ${{ secrets.TEST_PASS }}
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-html-report
path: playwright-report/
retention-days: 14 Common Pitfalls
- Using waitForTimeout — Fixed sleeps make tests flaky; use auto-waiting assertions instead
- Hardcoded CSS selectors — They break on styling changes; prefer getByRole or getByLabel
- Logging in before every test — Use storageState reuse; auth per-test multiplies runtime
- Missing --with-deps in CI — Playwright browsers need OS-level deps; always use --with-deps on Linux
- No artifacts on failure — Always upload playwright-report as a CI artifact for visual debugging
- Testing implementation details — Assert visible outcomes (text, URL, ARIA state), not internal state
Frequently Asked Questions
How do I record a Playwright test using the codegen command?▼
Run npx playwright codegen <url> in your terminal. A Chromium browser opens alongside a code inspector window. Every action you take is recorded as Playwright code in real time. Use --browser firefox or --browser webkit to record in different browsers. The --save-storage flag persists authentication cookies between recording sessions.
What is the difference between getByRole, getByText, and getByTestId?▼
Playwright recommended priority: getByRole (ARIA role + accessible name) > getByLabel > getByPlaceholder > getByText > getByTestId. getByRole is the most resilient because it reflects how users and assistive technology experience the page. Avoid CSS selectors and XPath — they break when styling or DOM structure changes.
How do I handle authentication in Playwright tests?▼
Use storageState to save and reuse sessions. Run a global setup file that logs in once and saves the browser state (cookies + localStorage) with page.context().storageState(). In playwright.config.ts, set storageState for authenticated projects. This avoids logging in before every test and speeds up the suite dramatically.
How do I wait for elements without using fixed sleeps?▼
Playwright has auto-waiting built in — most actions automatically wait for the element to be visible, stable, and enabled. Use await expect(locator).toBeVisible() for explicit waits. Use page.waitForResponse() for network calls and page.waitForURL() after navigation. Never use page.waitForTimeout() — it creates brittle tests that fail under slow CI conditions.
How do I run Playwright tests in CI/CD?▼
Install browsers in CI with npx playwright install --with-deps. Run tests headlessly (the default) with npx playwright test. Use --workers=4 to parallelize. The --reporter=html flag generates an HTML report — upload it as a CI artifact. Use shards (--shard=1/4) to split the suite across multiple runners for faster feedback.
What is Playwright page object model and should I use it?▼
The Page Object Model wraps each page into a class with methods for actions and assertions. Instead of repeating selectors, you call loginPage.fillCredentials(user, pass). For large suites POM reduces duplication. For small suites it adds unnecessary boilerplate. Playwright fixtures are the modern alternative — create fixtures that instantiate page objects, making them injectable into any test.
Related Products
on GumroadGitHub Actions CI/CD Templates Pack
12 production-ready GitHub Actions workflow templates covering Node.js, Python, Docker, multi-environment deployments, security scanning, and auto-changelog. Copy, paste, ship.
Buy on Gumroad →Premium Workflow Pack
Production-grade workflows, architecture guides, and deployment scripts for teams that ship. 10 advanced CI/CD workflows (blue-green, canary, E2E, security), 5 architecture deep-dives, code review checklist, PR process guide, and 5 battle-tested Bash deployment scripts.
Buy on Gumroad →Developer Productivity Bundle
Stop rebuilding the same setup every project. 51 VSCode snippets, 40 Git aliases, 5 Docker Compose stacks, 5 GitHub Actions workflows, 5 README templates, and a dotfiles kit. Set up a professional dev environment in under an hour.
Buy on Gumroad →You Might Also Need
Playwright Config Generator
Build a playwright.config.ts file visually. Configure browsers, timeouts, retries, reporters, screenshots, video, trace, and web server settings. Copy-ready TypeScript or JavaScript output.
Open free tool →
Playwright E2E Test Generator
Generate Playwright end-to-end test code visually. Add click, fill, expect, and navigate steps, toggle TypeScript/JavaScript, and copy the test code.
Open free tool →
Playwright E2E Testing Guide
Complete Playwright end-to-end testing guide. Learn locators, auto-wait, fixtures, network interception, API testing, Trace Viewer, and multi-browser automation.
Open free tool →
More Free Tools
Related Articles
Playwright E2E Testing Guide 2026: Complete Setup & Best Practices
A complete guide to Playwright end-to-end testing in 2026. Covers installation, Page Object Model, visual regression, parallel execution, GitHub Actions CI, and debugging techniques with TypeScript examples.
End-to-End Testing in 2026: Writing Tests That Don't Lie
E2E testing guide 2026: choose Playwright or Cypress, eliminate flakiness, structure test suites for CI/CD, and understand real application quality limits.
Playwright vs Selenium 2026: Which Should You Choose?
Complete comparison of Playwright and Selenium for browser automation and end-to-end testing in 2026. Performance benchmarks, API differences, migration guide, and when to use each.
DevOps Automation Tools in 2026: Orchestrating the Software Delivery Pipeline
Master DevOps automation with this guide to the tools that orchestrate modern software delivery. Covers CI/CD pipelines, infrastructure provisioning, configuration management, testing automation, and the emerging AI-assisted automation patterns that define 2026.
QA Automation in 2026: From Script Kiddies to Intelligent Test Suites
How modern QA automation has evolved in 2026 — AI-driven test generation, self-healing frameworks, shift-left strategies, and the real cost of not automating. A practical guide for teams still writing tests manually.
Enjoying this tool? Get more like it.
Weekly developer tool guides, productivity playbooks & AI tricks. Free. No spam.
Unlock AI-Powered Dev Tools
- ⚡ AI Code Review, Doc Generator & SQL Builder
- ⚡ All premium templates & early access
- ⚡ Member discounts on Gumroad products
$9/mo after trial · Cancel anytime
Want the full toolkit?
Get DevPlaybook Pro
Every template, guide, boilerplate, and automation script in one bundle. 13 premium products — grab them all at once and save big.
MIT licensed · Instant download · No subscription
See what's included → Browse all deals →