Introduction
Playwright is an open-source framework from Microsoft for browser automation, outperforming Selenium in speed and reliability. In 2026, it natively supports Chromium, Firefox, and WebKit with an intuitive API for robust end-to-end (E2E) tests. Why use it? It manages isolated contexts, mobile emulations, and parallel tests with minimal flakiness, cutting false positives by 80% compared to legacy tools.
This beginner tutorial takes you from the basics to actionable tests: installation, setup, page interactions, and assertions. By the end, you'll have a testable project on a simple HTML page, ready to scale. Imagine testing a login form in just 10 lines of code instead of complex setups—that's Playwright's power. (132 words)
Prerequisites
- Node.js 20+ installed
- Basic JavaScript/TypeScript knowledge
- An editor like VS Code
- Git for version control (optional)
Initialize the project and install Playwright
mkdir playwright-demo
cd playwright-demo
npm init -y
npm install -D @playwright/test
type "npx playwright install" && npx playwright installThis command creates a project folder, initializes npm, and installs Playwright as a dev dependency. npx playwright install downloads the browser binaries (Chromium by default). Don't skip this step: without it, tests fail with 'browser not found' errors.
Understanding the project structure
After installation, Playwright creates a tests/ folder with example.spec.ts. Also create tests/demo.html for our examples:
html
Playwright Demo
Result here
Serve it locally with npx serve . at http://localhost:3000.
Configure Playwright
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});This file centralizes the config: test directory, HTML reporters for visual reports, baseURL for relative URLs, and a Chromium project. trace: 'on-first-retry' captures videos/screenshots on failures. Pitfall: without baseURL, every page.goto() needs an absolute URL, bloating your code.
First test: basic navigation
import { test, expect } from '@playwright/test';
test('basic navigation', async ({ page }) => {
await page.goto('/demo.html');
await expect(page).toHaveTitle(/Demo/);
await expect(page.locator('h1')).toHaveText('Playwright Demo');
});This test navigates to the page, checks the title, and the h1 with assertions. expect(page) tests the entire document; locator targets precisely. It runs standalone: copy-paste and launch. Skip page.waitForLoadState() here—expect waits implicitly.
Run your first tests
Tip: Run npx playwright test for all tests, or npx playwright test first.spec.ts for one. Open playwright-report/index.html for an interactive dashboard with videos and traces.
Interaction test: clicks and input
import { test, expect } from '@playwright/test';
test('user interactions', async ({ page }) => {
await page.goto('/demo.html');
const button = page.locator('#btn');
const input = page.locator('#input');
const result = page.locator('#result');
await button.click();
await input.fill('Test Playwright');
await input.press('Enter');
await expect(result).toHaveText('Test Playwright clicked!');
});Simulates a click, typing, and Enter on elements. locator('#id') is robust to DOM changes. Use await result.toContainText('...') for flexibility. Pitfall: without press('Enter'), key events don't fire, breaking JS validations.
Test with advanced assertions
import { test, expect } from '@playwright/test';
test('advanced assertions', async ({ page }) => {
await page.goto('/demo.html');
await expect(page.locator('#btn')).toBeVisible();
await expect(page.locator('#input')).toBeEnabled();
await page.locator('#input').fill('Hello');
await expect(page.locator('#input')).toHaveValue('Hello');
await expect(page).toHaveScreenshot('demo-page.png');
});Checks visibility, enabled state, and input value, plus a pixel-perfect screenshot. toHaveScreenshot captures and compares images. Update baselines with test --update-snapshots. Caution: high-DPI screens break snapshots; set viewport in config.
Multi-browser testing
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
});Adds Firefox and WebKit projects for cross-browser parallel tests. Run npx playwright test --project=chromium to target one. Pitfall: JS behaviors vary (e.g., Safari userAgent); try devices['iPhone 12'] for mobile.
Run tests in UI mode
npx playwright test --ui
npx playwright test --headed --slow-mo=500
npx playwright show-trace tests/interactions.spec.ts/1/trace.zip--ui opens an interactive dashboard for debugging. --headed shows the browser, --slow-mo slows it down to watch. show-trace replays failures. Perfect for beginners: visualize step-by-step without cryptic logs.
Best practices
- Use text locators:
page.getByText('Click me')over fragile CSS. - Custom fixtures: Create
test.extend({ user: async ({}, use) => { ... } })for reusable setups. - Isolated tests: One
test= one feature; usetest.describefor logical suites. - Error handling: Add conditional
test.skip(condition)andtest.fail(). - CI/CD: Integrate with GitHub Actions using
playwright-github-action.
Common errors to avoid
- Server not running: Always start
npx servebefore tests; otherwise,gototimes out. - Unstable selectors: Avoid
page.click('button:nth-child(2)'); prefergetByRole('button', { name: /text/ }). - Default timeouts: Use
expect({ timeout: 10000 })for slow pages, but investigate root causes. - Missing browsers: Run
npx playwright install --with-depson Linux for system libs.
Next steps
- Official docs: playwright.dev
- Advanced: API tests with
requestfixture, component testing with@playwright/experimental-ct-react. - Training: Check out our QA automation courses at Learni to master Playwright in production.
- Example repo: Clone this tutorial on GitHub to experiment.