Playwright Test is a test framework from Microsoft that runs real browser tests — Chromium, Firefox, WebKit — in parallel, with auto-waiting and trace debugging.
Why Playwright Test?
- 3 browsers — Chromium, Firefox, WebKit in one framework
- Auto-waiting — no manual waits, elements resolve automatically
- Parallel — tests run in parallel across browsers
- Trace viewer — time-travel debugging for failed tests
Quick Start
npm init playwright@latest
npx playwright test
Writing Tests
import { test, expect } from '@playwright/test';
test('user can sign up', async ({ page }) => {
await page.goto('https://myapp.com/signup');
await page.fill('[name="email"]', 'alice@example.com');
await page.fill('[name="password"]', 'secure123');
await page.click('button[type="submit"]');
await expect(page.locator('h1')).toHaveText('Welcome, Alice!');
});
test('search returns results', async ({ page }) => {
await page.goto('https://myapp.com');
await page.fill('[name="search"]', 'typescript');
await page.press('[name="search"]', 'Enter');
await expect(page.locator('.results')).toContainText('TypeScript');
const count = await page.locator('.result-item').count();
expect(count).toBeGreaterThan(0);
});
Page Object Model
class LoginPage {
constructor(private page: Page) {}
async login(email: string, password: string) {
await this.page.fill('#email', email);
await this.page.fill('#password', password);
await this.page.click('#submit');
}
async expectError(message: string) {
await expect(this.page.locator('.error')).toHaveText(message);
}
}
test('login with wrong password', async ({ page }) => {
const loginPage = new LoginPage(page);
await page.goto('/login');
await loginPage.login('alice@example.com', 'wrong');
await loginPage.expectError('Invalid credentials');
});
API Testing
test('API returns users', async ({ request }) => {
const response = await request.get('/api/users');
expect(response.ok()).toBeTruthy();
const users = await response.json();
expect(users.length).toBeGreaterThan(0);
expect(users[0]).toHaveProperty('email');
});
test('API creates user', async ({ request }) => {
const response = await request.post('/api/users', {
data: { name: 'Bob', email: 'bob@test.com' },
});
expect(response.status()).toBe(201);
});
Visual Regression
test('homepage matches screenshot', async ({ page }) => {
await page.goto('https://myapp.com');
await expect(page).toHaveScreenshot('homepage.png', {
maxDiffPixelRatio: 0.01,
});
});
Configuration
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
retries: 2,
workers: 4,
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
projects: [
{ name: 'chromium', use: devices['Desktop Chrome'] },
{ name: 'firefox', use: devices['Desktop Firefox'] },
{ name: 'webkit', use: devices['Desktop Safari'] },
{ name: 'mobile', use: devices['iPhone 14'] },
],
});
Testing scraping tools? Check out my Apify actors for production-tested web scrapers, or email spinov001@gmail.com for custom testing solutions.
Playwright, Cypress, or Selenium — which E2E framework do you use? Share below!
Top comments (0)