Day 1: Welcome to Playwright
What You'll Learn Today
- What E2E testing is and why it matters
- The testing pyramid concept (Unit, Integration, E2E)
- What Playwright is, its features, and advantages
- Playwright vs other tools (Cypress, Selenium) comparison
- Playwright architecture (browser automation via protocols)
- Installation and initial setup
- Writing and running your first test
- Understanding test results
What Is E2E Testing?
When building web applications, you need to verify that entire user workflows function correctly β things like "Can a user log in with valid credentials?" or "Can a customer add items to their cart and complete checkout?" Manually checking all of this after every code change is slow, tedious, and error-prone.
E2E (End-to-End) testing is a testing approach that automates real browser interactions to verify your application works correctly from the user's perspective, covering the full stack from the UI down to the database.
flowchart LR
subgraph Manual["Manual Testing"]
M1["Open the browser"]
M2["Fill in the form"]
M3["Click the button"]
M4["Visually verify results"]
end
subgraph E2E["E2E Testing (Automated)"]
E1["page.goto()"]
E2["page.fill()"]
E3["page.click()"]
E4["expect() auto-verifies"]
end
M1 --> M2 --> M3 --> M4
E1 --> E2 --> E3 --> E4
style Manual fill:#f59e0b,color:#fff
style E2E fill:#22c55e,color:#fff
Why Do We Need E2E Testing?
| Problem | How E2E Testing Helps |
|---|---|
| Manual testing is time-consuming | Automated tests finish in minutes |
| Humans make mistakes | Tests execute the same steps accurately every time |
| Regressions are hard to detect | Automatically checks the entire app after every change |
| Cross-browser verification is tedious | Run automatically across Chromium, Firefox, and WebKit |
| Quality assurance in CI/CD | Validates quality automatically before deployment |
The Testing Pyramid
Software testing comes in several types depending on scope and purpose. The testing pyramid provides a systematic framework for thinking about how many tests of each type you should write.
flowchart TB
subgraph Pyramid["Testing Pyramid"]
E2E["E2E Tests\n(Few Β· High cost Β· High confidence)"]
INT["Integration Tests\n(Moderate)"]
UNIT["Unit Tests\n(Many Β· Low cost Β· Fast)"]
end
E2E --> INT --> UNIT
style E2E fill:#ef4444,color:#fff
style INT fill:#f59e0b,color:#fff
style UNIT fill:#22c55e,color:#fff
| Test Type | Scope | Speed | Cost | Example |
|---|---|---|---|---|
| Unit Tests | Individual functions/components | Fast | Low | Testing an input validation function |
| Integration Tests | Multiple components working together | Moderate | Moderate | Testing API and database interaction |
| E2E Tests | The entire application | Slow | High | User registration through login flow |
E2E tests sit at the top of the pyramid. While you write fewer of them, they cover the most critical user scenarios. Playwright is the tool that makes writing and running these E2E tests efficient and reliable.
What Is Playwright?
Playwright is an open-source E2E testing and browser automation framework developed by Microsoft. Released in 2020, it has rapidly gained adoption and is now one of the leading E2E testing tools in the industry.
Key Features of Playwright
flowchart TB
subgraph Features["Playwright Features"]
A["Multi-browser Support\nChromium / Firefox / WebKit"]
B["Auto-waiting\nBuilt-in Smart Waits"]
C["Test Isolation\nBrowser Contexts"]
D["Parallel Execution\nWorker Processes"]
E["Powerful Debugging\nTrace Viewer / Inspector"]
F["Multi-language\nTS / JS / Python / Java / C#"]
end
style Features fill:#3b82f6,color:#fff
style A fill:#8b5cf6,color:#fff
style B fill:#8b5cf6,color:#fff
style C fill:#8b5cf6,color:#fff
style D fill:#8b5cf6,color:#fff
style E fill:#8b5cf6,color:#fff
style F fill:#8b5cf6,color:#fff
- Multi-browser support: Test on Chromium (Chrome, Edge), Firefox, and WebKit (Safari) with a single API
- Auto-waiting: Playwright automatically waits for elements to be actionable before performing actions β no explicit waits or sleeps needed
- Test isolation: Each test runs in its own Browser Context, ensuring tests never interfere with each other
- Parallel execution: Tests run in parallel across worker processes, dramatically reducing total test time
- Powerful debugging: Trace Viewer, UI Mode, and Playwright Inspector provide deep insight into test execution
- Multi-language support: Available for TypeScript/JavaScript, Python, Java, and C#
Playwright vs Other Tools
Selenium / Cypress / Playwright Comparison
| Feature | Selenium | Cypress | Playwright |
|---|---|---|---|
| Developer | ThoughtWorks (2004) | Cypress.io (2017) | Microsoft (2020) |
| Browsers | All major browsers | Chromium, Firefox, WebKit | Chromium, Firefox, WebKit |
| Languages | Java, Python, C#, JS, etc. | JavaScript/TypeScript | JS/TS, Python, Java, C# |
| Architecture | WebDriver protocol | Runs inside the browser | CDP / browser protocols |
| Auto-waiting | No (manual implementation) | Yes | Yes (more precise) |
| Parallel execution | Requires external tools | Limited | Built-in |
| Multiple tabs/windows | Supported | Not supported | Supported |
| iframe handling | Possible (verbose) | Possible (limited) | Easy |
| Network interception | Limited | Powerful | Powerful |
| Execution speed | Slow | Fast | Very fast |
| Learning curve | Moderate | Low | Low |
Why Choose Playwright?
- Over Selenium: Auto-waiting, simple setup, faster execution, modern API
- Over Cypress: Multiple tabs and iframe support, true multi-browser testing, built-in parallel execution
Playwright Architecture
Understanding how Playwright controls browsers under the hood helps you write better tests and debug issues more effectively.
flowchart LR
subgraph TestProcess["Test Process"]
T["Test Code\n(TypeScript)"]
PW["Playwright\nLibrary"]
end
subgraph BrowserProcess["Browser Process"]
B["Browser Engine\n(Chromium/Firefox/WebKit)"]
P["Page"]
end
T --> PW
PW -->|"CDP / Browser Protocol"| B
B --> P
style TestProcess fill:#3b82f6,color:#fff
style BrowserProcess fill:#8b5cf6,color:#fff
Communication Protocols
Playwright uses each browser engine's native protocol for communication.
| Browser | Protocol | Description |
|---|---|---|
| Chromium | Chrome DevTools Protocol (CDP) | The same protocol used by Chrome DevTools |
| Firefox | Playwright protocol (custom patches) | Optimized protocol for Firefox |
| WebKit | Playwright protocol (custom patches) | Optimized protocol for WebKit |
How It Differs from Cypress
Cypress runs test code directly inside the browser in an iframe. Playwright, on the other hand, keeps the test process and browser process separate. This architectural decision enables:
- Multiple browser control: Since browsers run as separate processes, Playwright can control multiple browsers simultaneously
- Multiple tabs and windows: Controlling from outside the browser means no restrictions on tab or window management
- Network-level control: HTTP requests and responses can be intercepted from outside the browser
Installation and Initial Setup
Prerequisites
- Node.js: Version 18 or higher
- npm: Bundled with Node.js
- OS: Windows, macOS, or Linux
Creating a New Project
Let's create a new project and set up Playwright.
# Create a new directory
mkdir my-playwright-project
cd my-playwright-project
# Initialize a Playwright project
npm init playwright@latest
The initialization wizard will ask:
? Do you want to use TypeScript or JavaScript? Β· TypeScript
? Where to put your end-to-end tests? Β· tests
? Add a GitHub Actions workflow? Β· false
? Install Playwright browsers? Β· true
Generated File Structure
my-playwright-project/
βββ tests/
β βββ example.spec.ts # Sample test file
βββ tests-examples/
β βββ demo-todo-app.spec.ts # Todo app demo test
βββ playwright.config.ts # Playwright configuration
βββ package.json
βββ package-lock.json
βββ tsconfig.json
Understanding playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
// Directory containing test files
testDir: './tests',
// Timeout for each test (30 seconds)
timeout: 30000,
// Run tests in parallel
fullyParallel: true,
// Enable retries in CI
retries: process.env.CI ? 2 : 0,
// Number of parallel workers
workers: process.env.CI ? 1 : undefined,
// Test reporter
reporter: 'html',
// Shared settings for all tests
use: {
// Base URL for navigation
baseURL: 'http://localhost:3000',
// Record trace on first retry
trace: 'on-first-retry',
// Screenshot settings
screenshot: 'only-on-failure',
},
// Browser configurations
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
});
Key Configuration Options
| Option | Default | Description |
|---|---|---|
testDir |
'./tests' |
Directory containing test files |
timeout |
30000 | Timeout per test in milliseconds |
fullyParallel |
true | Enable fully parallel test execution |
retries |
0 | Number of retries on failure |
workers |
50% of CPU cores | Number of parallel worker processes |
reporter |
'list' |
Test reporter type |
use.baseURL |
none | Base URL for page.goto('/') |
use.trace |
'off' |
When to record traces |
Writing Your First Test
Basic Test Structure
Playwright tests use the test function and expect assertions.
// tests/my-first-test.spec.ts
import { test, expect } from '@playwright/test';
test('can access the Playwright website', async ({ page }) => {
// 1. Navigate to the page
await page.goto('https://playwright.dev/');
// 2. Verify the title contains "Playwright"
await expect(page).toHaveTitle(/Playwright/);
// 3. Verify the "Get started" link is visible
const getStarted = page.getByRole('link', { name: 'Get started' });
await expect(getStarted).toBeVisible();
});
Running Tests
# Run all tests
npx playwright test
# Run a specific test file
npx playwright test tests/my-first-test.spec.ts
# Run with a specific browser
npx playwright test --project=chromium
# Run in UI mode (interactive)
npx playwright test --ui
# Run in headed mode (browser visible)
npx playwright test --headed
Writing Multiple Tests
// tests/example.spec.ts
import { test, expect } from '@playwright/test';
test.describe('Playwright website', () => {
test('can access the homepage', async ({ page }) => {
await page.goto('https://playwright.dev/');
await expect(page).toHaveTitle(/Playwright/);
});
test('can navigate to Get Started page', async ({ page }) => {
await page.goto('https://playwright.dev/');
// Click the "Get started" link
await page.getByRole('link', { name: 'Get started' }).click();
// Verify the Installation heading is visible
await expect(
page.getByRole('heading', { name: 'Installation' })
).toBeVisible();
});
test('search functionality works', async ({ page }) => {
await page.goto('https://playwright.dev/');
// Click the search button
await page.getByRole('button', { name: 'Search' }).click();
// Verify the search dialog appears
await expect(page.getByRole('dialog')).toBeVisible();
});
});
Understanding Test Results
Command Line Output
When you run tests, you'll see output like this:
Running 3 tests using 3 workers
β 1 [chromium] βΊ example.spec.ts:4:3 βΊ Playwright website βΊ can access the homepage (1.2s)
β 2 [chromium] βΊ example.spec.ts:9:3 βΊ Playwright website βΊ can navigate to Get Started page (1.8s)
β 3 [chromium] βΊ example.spec.ts:20:3 βΊ Playwright website βΊ search functionality works (1.5s)
3 passed (4.2s)
Test Result Statuses
| Status | Symbol | Meaning |
|---|---|---|
| Passed | β | Test succeeded |
| Failed | β | Test failed |
| Skipped | - | Test was skipped |
| Timed out | β | Failed due to timeout |
| Flaky | β | Passed after retry (unstable test) |
HTML Report
Playwright can generate detailed HTML reports for your test runs.
# View the HTML report
npx playwright show-report
The HTML report provides:
- An overview of all test results
- Execution time for each test
- Error messages for failed tests
- Screenshots (when configured)
- Trace information (when configured)
Trace Viewer
The Trace Viewer is an invaluable tool for investigating why tests fail.
// Enable trace recording in playwright.config.ts
use: {
trace: 'on-first-retry', // Record trace on first retry
}
The Trace Viewer shows:
- Screenshots at each step of the test
- DOM snapshots at the time of each action
- Network requests and responses
- Console logs from the browser
# Open a trace file
npx playwright show-trace trace.zip
Summary
| Concept | Description |
|---|---|
| E2E Testing | Tests that automate user interactions to verify the entire application |
| Testing Pyramid | Three-layer structure: Unit β Integration β E2E. Focus E2E on critical scenarios |
| Playwright | Microsoft's multi-browser E2E testing framework |
| Auto-waiting | Playwright automatically waits for elements to be actionable |
| Browser Context | Isolated browser environment ensuring test independence |
| CDP | Chrome DevTools Protocol β how Playwright communicates with Chromium |
| Trace Viewer | Debugging tool that provides detailed step-by-step test execution analysis |
Key Points
- E2E tests are essential for automating manual testing and preventing regressions
- Playwright controls browsers from outside the process, enabling multiple tabs and iframe manipulation
- Auto-waiting eliminates the need for explicit sleep or wait calls in your test code
npm init playwright@latestprovides a quick and easy project setup
Practice Exercises
Exercise 1: Basic
Explain the three layers of the testing pyramid, providing specific examples of tests you would write at each layer. Why are E2E tests placed at the top of the pyramid?
Exercise 2: Intermediate
Compare the architectures of Playwright and Cypress. List three advantages that Playwright's out-of-process architecture provides, and explain specifically why it enables multiple tab operations.
Challenge Exercise
Set up a new project using npm init playwright@latest and create tests that meet the following requirements:
- Modify
playwright.config.tsto run tests only on Chromium - Write a test that navigates to a website of your choice
- Include assertions for the page title and visibility of a specific element
- Run the tests with
npx playwright testand review the HTML report
Reference Links
- Playwright Official Documentation
- Playwright GitHub Repository
- The Testing Pyramid - Martin Fowler
- Chrome DevTools Protocol
Next Preview: In Day 2, we'll explore Test Structure Fundamentals. You'll learn about test.describe, test.beforeEach, test.afterEach, and how Playwright's fixture system works.