
Testing web applications is essential for modern software development. Whether you’re launching a startup site or managing enterprise-scale systems, automated testing ensures speed and quality.
Playwright, developed by Microsoft, empowers developers to create end-to-end tests that mimic real user interactions like clicking buttons, filling forms, or navigating between pages across all major browsers.
This guide shows you how to write and run your first Playwright test in JavaScript. You’ll learn not just the technical steps but also how Playwright works behind the scenes and why it’s now a preferred framework among QA engineers and developers alike.
Playwright is an open-source automation framework that enables web testing across browsers, devices, and operating systems using a single API.
Chromium (Chrome, Edge)
Firefox
WebKit (Safari)
UI and API testing
Visual comparison and performance tracking
Network interception and mocking
One API for all browsers
Built-in auto-wait to prevent flaky tests
Deep network control
Parallel and cross-browser execution
Integrated test runner and reporting tools
Before writing your first test, prepare your environment.
Prerequisites:
Node.js v16 or higher
NPM (bundled with Node.js)
Code editor (VS Code recommended)
Check installation:
node -v
npm -v
If both commands return versions, you’re ready.
Step 1: Create a project folder
mkdir playwright-demo
cd playwright-demo
Step 2: Initialize Node.js
npm init -y
Step 3: Install Playwright
npm install @playwright/test --save-dev
Step 4: Install browsers
npx playwright install
This downloads Chromium, Firefox, and WebKit.
playwright-demo/
├── tests/
│ └── firstTest.spec.js
├── playwright.config.js
├── package.json
└── node_modules/
Purpose of key files:
tests/ → Store your test scripts
playwright.config.js → Define global settings
package.json → Manage dependencies
Create tests/firstTest.spec.js:
const { test, expect } = require('@playwright/test');
test('Verify page title and content', async ({ page }) => {
await page.goto('https://example.com');
await expect(page).toHaveTitle(/Example Domain/);
const heading = await page.locator('h1');
await expect(heading).toHaveText('Example Domain');
const moreInfo = await page.locator('a');
await moreInfo.click();
await expect(page).toHaveURL(/iana.org/);
});
This test opens a page, checks the title, validates content, and follows a link replicating real user behavior.
| Code Line | Explanation |
|---|---|
const { test, expect } = require('@playwright/test') |
Imports Playwright’s test runner and assertions |
page.goto(url) |
Navigates to the specified URL |
expect(page).toHaveTitle() |
Validates the page title |
locator(selector) |
Locates an element on the page |
click() |
Performs a simulated click |
await |
Ensures sequential, reliable execution |
Playwright’s async/await model guarantees stability and accuracy.
Run in terminal:
npx playwright test
You’ll see output such as:
Running 1 test using 1 worker
✓ tests/firstTest.spec.js (5s)
Playwright launches the browser, runs the steps, and displays results.
By default, Playwright runs headless (without a visible browser).
To watch your test:
npx playwright test --headed
This is useful for debugging and demonstrations.
Target specific browsers:
npx playwright test --project=chromium
npx playwright test --project=firefox
npx playwright test --project=webkit
Or run all simultaneously:
npx playwright test --parallel
Create a playwright.config.js file:
Now tests automatically run on multiple browsers with consistent settings.
Behind the scenes:
Launches a browser engine
Opens a fresh browser context
Creates a new page (tab)
Executes your test commands via the Playwright API
Waits automatically for elements to appear
Closes the browser and reports results
This flow ensures reliability and isolation for each test.
Common Playwright assertions:
| Assertion | Purpose |
|---|---|
toHaveTitle() |
Verify page title |
toHaveURL() |
Confirm current URL |
toHaveText() |
Match element text |
toBeVisible() |
Ensure element visibility |
toBeEnabled() |
Validate enabled state |
Assertions transform automated steps into meaningful validations.
Option 1: Debug Mode
npx playwright test --debug
Option 2: Pause Execution
await page.pause();
Option 3: Generate HTML Report
npx playwright show-report
You can inspect screenshots, logs, and step details visually.
Add screenshots in your test:
await page.screenshot({ path: 'homepage.png' });
Enable video capture globally:
use: { video: 'on' }
These artifacts are invaluable for troubleshooting.
Parallel: Faster test runs using multiple workers
Sequential: One test at a time for controlled execution
Example:
npx playwright test --parallel
Each test runs in its own isolated browser context.
Hooks streamline repetitive actions:
test.beforeEach(async ({ page }) => {
await page.goto('https://example.com');
});
test.afterEach(async ({ page }) => {
await page.close();
});
test.describe('Login Suite', () => {
test('Valid login', async ({ page }) => { /* code */ });
test('Invalid login', async ({ page }) => { /* code */ });
});
Grouping simplifies management of related test cases.
| Mistake | Correction |
|---|---|
Using waitForTimeout() |
Rely on auto-wait instead |
Skipping await |
Always use await |
| Hardcoding credentials | Use environment variables |
| Forgetting browser cleanup | Use hooks |
| No assertions | Always validate results |
Following best practices ensures stable, repeatable automation.
test('Valid user login', async ({ page }) => {
await page.goto('https://example-login.com');
await page.fill('#username', 'demoUser');
await page.fill('#password', 'password123');
await page.click('button[type="submit"]');
await expect(page).toHaveURL(/dashboard/);
await expect(page.locator('h1')).toHaveText('Welcome, demoUser');
});
This scenario verifies a successful login and dashboard redirect.
Example GitHub Actions workflow:
name: Playwright Tests
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm ci
- run: npx playwright install
- run: npx playwright test
Use data-test attributes for selectors
Organize tests by modules or features
Store credentials securely in .env files
Run tests headless in CI environments
Integrate API testing using Playwright’s network control
You’ve now written and executed your first Playwright test.
You’ve learned to:
Install and configure Playwright
Write tests using async/await
Debug, capture reports, and integrate CI/CD
These foundations prepare you for advanced concepts like API testing, visual regression, and parallel execution across environments.
Q1. What languages does Playwright support?
Ans: JavaScript, TypeScript, Python, Java, and .NET.
Q2. How does it differ from Selenium?
Ans: Playwright uses WebSocket communication, built-in waits, and supports multiple sessions making it faster and more stable.
Q3. Can Playwright emulate mobile browsers?
Ans: Yes, it supports device emulation for iPhone and Android.
Q4. Is it beginner-friendly?
Ans: Absolutely clean syntax, robust docs, and a built-in test runner make learning straightforward.
Q5. Does Playwright support parallel testing?
Ans: Yes, with isolated browser contexts per test file.
Automation isn’t about memorizing commands it’s about mastering interaction. Playwright simplifies automation by bridging human-like browser actions with code precision.
By successfully writing and running your first test, you’ve taken a major step toward mastering modern web automation.
To deepen your understanding, explore [How to Set Up Playwright Software Testing in a JavaScript Project] for configuration essentials and [Playwright Architecture Explained: Browsers, Channels, and Contexts] for insights into how Playwright works under the hood.
Course :