Introduction: Why Learn Playwright in 2026?
Modern web applications are increasingly dynamic, distributed, and dependent on APIs. Traditional UI automation approaches can become difficult to maintain when applications contain asynchronous content, multiple browser engines, responsive layouts, and complex authentication flows.
This is why Playwright Automation Testing has become an important skill for QA Automation Engineers, SDETs, developers, and test engineers.
This playwright complete course tutorial is designed as a practical learning path from beginner concepts to advanced framework development.
You will learn how to install Playwright, write your first TypeScript test, work with locators and assertions, design Page Object Models, use fixtures, perform data-driven testing, authenticate users, test APIs, emulate mobile devices, run tests in parallel, debug failures, generate reports, use Docker, and integrate the framework with CI/CD.
The official Playwright project describes Playwright Test as an end-to-end framework that includes a test runner, assertions, isolation, parallelization, and tooling. It supports Chromium, Firefox, and WebKit, as well as native mobile emulation for selected configurations.
What Is Playwright?
Microsoft Playwright is an open-source browser automation framework for testing modern web applications.
It supports:
- Chromium
- Firefox
- WebKit
- Windows
- Linux
- macOS
- Mobile browser emulation
- API testing
- Screenshots
- Videos
- Trace Viewer
- Parallel execution
- CI/CD
A simplified architecture is:
Playwright
|
+————+————+
| | |
Chromium Firefox WebKit
| | |
+————+————+
|
Web Application
Playwright can also interact with APIs directly through APIRequestContext, which is useful for API testing and for preparing or validating server-side state around UI tests.
Why Learn Playwright for Automation Testing?
A Playwright complete course is valuable because modern QA roles increasingly require more than basic browser scripting.
You should understand:
| Skill | Why it matters |
| Playwright | Browser automation |
| TypeScript | Framework development |
| POM | Maintainability |
| Fixtures | Reusable setup |
| API testing | End-to-end coverage |
| Authentication | Real application workflows |
| CI/CD | Continuous testing |
| Docker | Consistent execution |
| Reporting | Failure analysis |
| Parallel execution | Faster regression |
Playwright vs Selenium vs Cypress
| Feature | Playwright | Selenium | Cypress |
| Chromium | Yes | Yes | Yes |
| Firefox | Yes | Yes | Yes |
| WebKit | Yes | Limited/varies by setup | No equivalent native engine |
| Mobile emulation | Yes | Via browser/device tooling | Yes, viewport-focused |
| API testing | Yes | External libraries commonly used | Yes |
| Multi-page workflows | Strong | Strong | Different architecture |
| Auto-waiting | Built in | More explicit synchronization often needed | Built in |
| TypeScript | Excellent | Available | Excellent |
| Parallel execution | Built in | Grid/setup commonly used | Available |
The best tool depends on the application and team. Playwright is particularly attractive when teams want cross-browser coverage, API capabilities, isolated browser contexts, modern locators, tracing, and an integrated test runner.
Playwright Installation and Project Setup
The easiest way to start this playwright complete course tutorial is with the official project generator.
npm init playwright@latest
Choose:
TypeScript
tests
Playwright’s installer creates files such as playwright.config.ts, package.json, and a starter test.
You can verify the installation:
npx playwright –version
npx playwright test
Open the HTML report:
npx playwright show-report
Playwright also provides UI Mode:
npx playwright test –ui
which is useful for interactive debugging and test development.
First Playwright Test with TypeScript
Create:
tests/homepage.spec.ts
import { test, expect } from ‘@playwright/test’;
test(‘homepage should load successfully’, async ({ page }) => {
await page.goto(‘https://playwright.dev/’);
await expect(page).toHaveTitle(/Playwright/);
await expect(
page.getByRole(‘heading’, {
name: /Playwright/
})
).toBeVisible();
});
Run:
npx playwright test tests/homepage.spec.ts
The { page } parameter is a built-in Playwright fixture that provides an isolated page for the test.
Playwright Locators, Assertions, and Auto-Waiting
Locators are central to Playwright.
Common locator methods include:
page.getByRole(‘button’, { name: ‘Login’ });
page.getByLabel(‘Email’);
page.getByPlaceholder(‘Search’);
page.getByText(‘Products’);
page.getByTestId(‘product-card’);
Example:
await page.getByLabel(‘Email’).fill(‘user@example.com’);
await page.getByLabel(‘Password’).fill(‘Password123’);
await page.getByRole(‘button’, {
name: ‘Login’
}).click();
Assertions:
await expect(page).toHaveURL(/dashboard/);
await expect(
page.getByText(‘Welcome’)
).toBeVisible();
Why auto-waiting matters
Modern applications frequently render elements asynchronously.
Instead of manually adding:
await page.waitForTimeout(3000);
prefer web-first assertions and locator actions.
For example:
await expect(
page.getByRole(‘button’, { name: ‘Checkout’ })
).toBeVisible();
await page.getByRole(‘button’, {
name: ‘Checkout’
}).click();
Avoid fixed sleeps whenever possible because they can make tests slower and less reliable.
Playwright Test Runner, Fixtures, Hooks, and Configuration
Playwright Test provides built-in fixtures such as:
- page
- context
- browser
- request
Fixtures establish the environment required by a test and are isolated between tests.
Example:
test(‘fixture example’, async ({
page,
context
}) => {
await page.goto(‘/’);
console.log(
await context.cookies()
);
});
Hooks
Use hooks for reusable setup:
test.beforeEach(async ({ page }) => {
await page.goto(‘/login’);
});
test.afterEach(async ({ page }) => {
console.log(‘Test completed’);
});
Configuration
A basic configuration:
import { defineConfig, devices } from ‘@playwright/test’;
export default defineConfig({
testDir: ‘./tests’,
use: {
baseURL: ‘https://example.com’,
screenshot: ‘only-on-failure’,
trace: ‘retain-on-failure’
},
projects: [
{
name: ‘chromium’,
use: {
…devices[‘Desktop Chrome’]
}
}
]
});
Keep common configuration in playwright.config.ts instead of duplicating it across tests.
Real-World Playwright Automation Examples
A beginner should practice different types of workflows rather than only writing simple navigation tests.
Login example
test(‘user login’, async ({ page }) => {
await page.goto(‘/login’);
await page.getByLabel(‘Email’)
.fill(process.env.TEST_USERNAME!);
await page.getByLabel(‘Password’)
.fill(process.env.TEST_PASSWORD!);
await page.getByRole(‘button’, {
name: ‘Login’
}).click();
await expect(page).toHaveURL(/dashboard/);
});
Use environment variables instead of hard-coded production credentials.
Registration example
test(‘user registration’, async ({ page }) => {
await page.goto(‘/register’);
await page.getByLabel(‘First name’)
.fill(‘Test’);
await page.getByLabel(‘Last name’)
.fill(‘User’);
await page.getByLabel(‘Email’)
.fill(`test-${Date.now()}@example.com`);
await page.getByLabel(‘Password’)
.fill(‘TestPassword123!’);
await page.getByRole(‘button’, {
name: ‘Register’
}).click();
await expect(
page.getByText(/registration successful/i)
).toBeVisible();
});
Forms, Dropdowns, and Dynamic Elements
For a native select:
await page.getByLabel(‘Country’)
.selectOption(‘IN’);
For a custom dropdown:
await page.getByRole(‘combobox’, {
name: ‘Country’
}).click();
await page.getByRole(‘option’, {
name: ‘India’
}).click();
For dynamic content:
await expect(
page.getByText(‘Order confirmed’)
).toBeVisible();
The goal is to wait for meaningful application state instead of arbitrary time periods.
File Upload and Download
File upload
await page.getByLabel(‘Upload document’)
.setInputFiles(‘test-data/document.pdf’);
File download
const downloadPromise =
page.waitForEvent(‘download’);
await page.getByRole(‘button’, {
name: ‘Download’
}).click();
const download = await downloadPromise;
await download.saveAs(
‘downloads/report.pdf’
);
These capabilities are useful for document-management, banking, HR, and e-commerce applications.
Playwright Page Object Model
Page Object Model separates page interaction logic from test scenarios.
Create:
pages/LoginPage.ts
import { Page } from ‘@playwright/test’;
export class LoginPage {
constructor(private page: Page) {}
private email = this.page.getByLabel(‘Email’);
private password = this.page.getByLabel(‘Password’);
private loginButton = this.page.getByRole(
‘button’,
{ name: ‘Login’ }
);
async open() {
await this.page.goto(‘/login’);
}
async login(
username: string,
password: string
) {
await this.email.fill(username);
await this.password.fill(password);
await this.loginButton.click();
}
}
Test:
import { test, expect } from ‘@playwright/test’;
import { LoginPage } from ‘../pages/LoginPage’;
test(‘login using POM’, async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.open();
await loginPage.login(
process.env.TEST_USERNAME!,
process.env.TEST_PASSWORD!
);
await expect(page).toHaveURL(/dashboard/);
});
A good POM framework centralizes locators and reusable actions while keeping test cases readable.
Playwright Data Driven Testing
Data-driven testing allows one test structure to run against multiple datasets.
const users = [
{
username: ‘user1@example.com’,
password: ‘Password123’
},
{
username: ‘user2@example.com’,
password: ‘Password456’
}
];
for (const user of users) {
test(`login – ${user.username}`, async ({ page }) => {
await page.goto(‘/login’);
await page.getByLabel(‘Email’)
.fill(user.username);
await page.getByLabel(‘Password’)
.fill(user.password);
await page.getByRole(‘button’, {
name: ‘Login’
}).click();
await expect(page).toHaveURL(/dashboard/);
});
}
For larger frameworks, test data can be stored in:
data/users.json
data/products.json
data/checkout.json
You can also use CSV files or generate data through APIs.
Playwright Authentication and Storage State
Authentication is one of the most important advanced Playwright topics.
Instead of logging in before every test, you can authenticate once and reuse the browser state.
Playwright supports storageState, which can preserve authenticated cookies and other storage information for later tests.
import { test as setup } from ‘@playwright/test’;
setup(‘authenticate’, async ({ page }) => {
await page.goto(‘/login’);
await page.getByLabel(‘Email’)
.fill(process.env.TEST_USERNAME!);
await page.getByLabel(‘Password’)
.fill(process.env.TEST_PASSWORD!);
await page.getByRole(‘button’, {
name: ‘Login’
}).click();
await page.context().storageState({
path: ‘playwright/.auth/user.json’
});
});
Then:
use: {
storageState: ‘playwright/.auth/user.json’
}
Security warning: authentication state files may contain sensitive cookies or headers. Playwright recommends keeping playwright/.auth out of source control.
Add:
playwright/.auth/
.env
to .gitignore.
Playwright API Testing
Playwright is not limited to browser UI automation.
The request fixture can send HTTP requests.
import { test, expect } from ‘@playwright/test’;
test(‘get products API’, async ({ request }) => {
const response = await request.get(‘/api/products’);
expect(response.ok()).toBeTruthy();
const products = await response.json();
expect(products.length).toBeGreaterThan(0);
});
You can also create server-side data:
const response = await request.post(‘/api/products’, {
data: {
name: ‘Test Laptop’,
price: 50000
}
});
expect(response.ok()).toBeTruthy();
This enables powerful hybrid testing:
API
↓
Create test data
↓
UI
↓
Perform workflow
↓
API
↓
Validate backend state
Playwright officially supports API requests for testing APIs, preparing server state, and validating postconditions after browser actions.
Playwright End-to-End Testing
End-to-end testing validates a complete business workflow.
For e-commerce:
Login
↓
Search product
↓
Open product
↓
Add to cart
↓
Checkout
↓
Place order
↓
Verify confirmation
Example:
test(‘complete shopping workflow’, async ({ page }) => {
await page.goto(‘/login’);
await page.getByLabel(‘Email’)
.fill(process.env.TEST_USERNAME!);
await page.getByLabel(‘Password’)
.fill(process.env.TEST_PASSWORD!);
await page.getByRole(‘button’, {
name: ‘Login’
}).click();
await page.getByPlaceholder(‘Search’)
.fill(‘laptop’);
await page.getByRole(‘button’, {
name: ‘Search’
}).click();
await page.getByText(‘Laptop’)
.first()
.click();
await page.getByRole(‘button’, {
name: /add to cart/i
}).click();
await page.getByRole(‘link’, {
name: /cart/i
}).click();
await expect(
page.getByText(/laptop/i)
).toBeVisible();
});
Playwright Mobile Emulation and Cross-Browser Testing
Playwright supports mobile emulation through device descriptors.
import { defineConfig, devices } from ‘@playwright/test’;
export default defineConfig({
projects: [
{
name: ‘Desktop Chrome’,
use: {
…devices[‘Desktop Chrome’]
}
},
{
name: ‘iPhone’,
use: {
…devices[‘iPhone 12’]
}
},
{
name: ‘Android’,
use: {
…devices[‘Pixel 5’]
}
}
]
});
Run a specific project:
npx playwright test –project=iPhone
This lets you validate responsive behavior without maintaining separate test suites.
Playwright Parallel Execution
Parallel execution is important when regression suites become large.
Run with workers:
npx playwright test –workers=4
Playwright isolates tests using browser contexts, helping tests execute independently.
However, parallel execution requires proper test-data isolation.
Avoid:
Test A → modifies same account
Test B → modifies same account
Prefer:
Worker 1 → Account A
Worker 2 → Account B
Worker 3 → Account C
Playwright recommends considering reduced worker counts in CI when stability and reproducibility are more important than maximum throughput.
Screenshots, Videos, Trace Viewer, and Reporting
Configure:
use: {
screenshot: ‘only-on-failure’,
video: ‘retain-on-failure’,
trace: ‘retain-on-failure’
}
Use the HTML reporter:
reporter: [
[‘html’],
[‘list’]
]
Run:
npx playwright test
Then:
npx playwright show-report
Trace Viewer is especially useful when a test passes locally but fails in CI.
You can inspect:
- Actions
- Screenshots
- DOM snapshots
- Network activity
- Timing
- Errors
For debugging browser-launch problems, Playwright also supports the DEBUG environment variable, such as DEBUG=pw:browser.
Playwright CI/CD with GitHub Actions
A basic workflow:
name: Playwright Tests
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
– uses: actions/checkout@v6
– uses: actions/setup-node@v6
with:
node-version: lts/*
– name: Install dependencies
run: npm ci
– name: Type check
run: npx tsc –noEmit
– name: Install Playwright
run: npx playwright install –with-deps
– name: Run tests
run: npx playwright test
– name: Upload report
if: ${{ !cancelled() }}
uses: actions/upload-artifact@v5
with:
name: playwright-report
path: playwright-report/
Playwright’s current CI guidance uses npm ci, browser installation with –with-deps, test execution, and report artifacts in GitHub Actions.
Type checking should be performed separately because Playwright transforms TypeScript for execution but does not perform complete type checking itself.
Docker and Playwright Automation
Docker provides a consistent environment for browser testing.
A simplified Dockerfile:
FROM mcr.microsoft.com/playwright:v1.62.0-noble
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD [“npx”, “playwright”, “test”]
Build:
docker build -t playwright-tests .
Run:
docker run –rm playwright-tests
Playwright publishes Docker images intended for browser testing in CI environments.
For production frameworks, pin the Playwright version and keep the container version aligned with the package version.
Real-World E-Commerce Playwright Automation Framework Project
A professional portfolio project should contain more than a collection of unrelated scripts.
Use this structure:
ecommerce-playwright/
│
├── tests/
│ ├── login.spec.ts
│ ├── search.spec.ts
│ ├── product.spec.ts
│ ├── cart.spec.ts
│ ├── checkout.spec.ts
│ └── api.spec.ts
│
├── pages/
│ ├── LoginPage.ts
│ ├── HomePage.ts
│ ├── ProductPage.ts
│ ├── CartPage.ts
│ └── CheckoutPage.ts
│
├── fixtures/
│ └── test.fixture.ts
│
├── data/
│ ├── users.json
│ └── products.json
│
├── playwright/
│ └── .auth/
│
├── .github/
│ └── workflows/
│ └── playwright.yml
│
├── Dockerfile
├── playwright.config.ts
├── package.json
└── README.md
Project functionality
Authentication
Implement:
- Login
- Logout
- Invalid credentials
- Storage state
Product search
Test:
- Search keyword
- Search results
- Filters
- Sorting
Product details
Test:
- Product name
- Price
- Description
- Images
- Add to cart
Shopping cart
Test:
- Add product
- Remove product
- Quantity
- Total
Checkout
Test:
- Customer information
- Shipping
- Payment
- Order confirmation
API testing
Use APIs to:
- Create products
- Prepare test data
- Validate orders
Framework features
Add:
- POM
- Fixtures
- Data-driven tests
- Authentication
- Cross-browser projects
- Mobile projects
- Parallel execution
- Screenshots
- Videos
- Traces
- HTML reports
- Docker
- GitHub Actions
This is a strong Playwright automation framework tutorial project because it demonstrates framework design rather than only individual test scripting.
Common Playwright Errors and Solutions
| Error | Likely cause | Solution |
| Locator not found | Wrong locator or page state | Inspect locator and use web-first assertions |
| Timeout | Element never became actionable | Check application state and locator |
| Browser launch failure | Missing dependencies | Run npx playwright install –with-deps |
| Test passes locally but fails CI | Environment difference | Use CI artifacts and traces |
| Authentication fails | Expired state | Regenerate storage state |
| Flaky tests | Shared state/timing | Isolate data and remove sleeps |
| Download fails | Event not handled | Wait for download event |
| Mobile test fails | Wrong project | Check device configuration |
| API test fails | Wrong endpoint/auth | Verify request and environment |
| TypeScript errors | No type-check stage | Run npx tsc –noEmit |
Playwright Best Practices
A professional framework should follow these principles.
1. Prefer user-facing locators
Use:
getByRole()
getByLabel()
getByText()
when appropriate.
2. Avoid hard waits
Don’t depend on:
await page.waitForTimeout(5000);
unless there is a specific reason.
3. Use Page Object Model carefully
POM should simplify tests, not become an enormous abstraction layer.
4. Keep test data separate
Use:
JSON
CSV
API-generated data
database fixtures
when appropriate.
5. Protect authentication state
Never commit:
playwright/.auth/
because it can contain sensitive browser state.
6. Make tests independent
A test should ideally be runnable by itself.
7. Use API setup where practical
Creating test data through APIs can be faster than navigating through the UI.
8. Use traces for CI failures
They dramatically reduce debugging time.
9. Run type checking separately
npx tsc –noEmit
10. Keep CI environments reproducible
Pin versions, standardize browsers, and use Docker where appropriate.
Playwright Interview Questions with Answers
1. What is Playwright?
Playwright is a browser automation and end-to-end testing framework supporting Chromium, Firefox, and WebKit.
2. Why use Playwright instead of Selenium?
Playwright provides built-in auto-waiting, browser contexts, tracing, modern locators, mobile emulation, API capabilities, and an integrated test runner.
Selenium remains widely used and has a mature ecosystem, so the right choice depends on the project’s requirements.
3. What is a browser context?
A BrowserContext is an isolated browser environment. It helps keep tests independent.
4. What are Playwright fixtures?
Fixtures establish the environment needed by tests, such as page, context, or custom resources.
5. What is storageState?
It stores browser authentication state so later tests can reuse authenticated sessions.
6. Can Playwright perform API testing?
Yes. APIRequestContext and the request fixture support HTTP API testing.
7. What is Page Object Model?
POM is a design pattern that encapsulates page locators and actions into reusable classes.
8. How does Playwright handle synchronization?
Playwright automatically waits for many actionability conditions and works well with web-first assertions.
9. Can Playwright run tests in parallel?
Yes. Playwright Test supports parallel execution and multiple workers.
10. How do you debug Playwright failures?
Use:
Trace Viewer
Screenshots
Videos
UI Mode
DEBUG logs
11. How do you run Playwright in CI?
Install dependencies and browsers, execute npx playwright test, and upload reports/artifacts.
12. What should an enterprise Playwright framework contain?
A strong framework may include:
TypeScript + POM + Fixtures + API Testing + Authentication + Data-Driven Testing + Reporting + CI/CD + Docker + Cross-Browser Testing.
Complete Playwright Learning Roadmap for Beginners
If you’re following this playwright complete course tutorial for beginners, don’t try to learn every advanced feature on day one.
Use this sequence.
Level 1: Fundamentals
Learn:
- What is Playwright?
- Installation
- Test structure
- Locators
- Assertions
- Auto-waiting
Level 2: Browser Automation
Practice:
- Login
- Registration
- Forms
- Dropdowns
- Checkboxes
- Radio buttons
- File upload
- Downloads
- Popups
- Frames
- Multiple tabs
Level 3: Test Framework
Learn:
- Fixtures
- Hooks
- Configuration
- Projects
- Test tags
- Retries
- Timeouts
- Parallel execution
Level 4: Framework Design
Learn:
- TypeScript
- Page Object Model
- Custom fixtures
- Test data
- Utilities
- Authentication
- API setup
Level 5: Advanced Testing
Learn:
- API testing
- Mobile emulation
- Visual testing
- Cross-browser testing
- Network mocking
- Storage state
- Parallel execution
Level 6: DevOps
Learn:
- Git
- GitHub Actions
- Docker
- CI/CD
- Reports
- Test artifacts
- Debugging failed pipelines
Level 7: Career Preparation
Build a portfolio framework and prepare for:
- Playwright interview questions
- Framework design questions
- Locator questions
- API testing questions
- CI/CD questions
- Debugging scenarios
- Parallel execution questions
- Authentication questions
FAQs: Playwright Complete Course Tutorial
What is Playwright?
Playwright is an automation framework for testing modern web applications across Chromium, Firefox, and WebKit.
How do I get started with Playwright?
Install it with:
npm init playwright@latest
Choose TypeScript and install the browsers.
Is Playwright good for beginners?
Yes. Beginners can start with locators and assertions, then gradually learn fixtures, POM, API testing, authentication, and CI/CD.
Does Playwright support TypeScript?
Yes. Playwright supports TypeScript out of the box. For reliable projects, run a separate TypeScript compiler check in addition to Playwright tests.
Can Playwright test APIs?
Yes. Playwright provides API request capabilities through APIRequestContext.
Can Playwright replace Selenium?
For many modern web automation projects, yes. However, Selenium remains a strong choice for organizations with established Selenium infrastructure, language requirements, or WebDriver-based ecosystems.
Does Playwright support mobile testing?
Yes. Playwright supports mobile browser emulation using device configurations.
Can Playwright run tests in parallel?
Yes. Playwright Test supports parallel workers and project-based execution.
Can Playwright run in Docker?
Yes. Playwright provides official Docker images for browser testing and CI environments.
Is Playwright useful for SDET jobs?
Yes. Combining Playwright with TypeScript, API testing, POM, fixtures, CI/CD, Docker, and reporting provides a strong automation engineering skill set.
