DEV Community

Alex Spinov
Alex Spinov

Posted on

Playwright Test Has a Free API — E2E Testing That Actually Works

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
Enter fullscreen mode Exit fullscreen mode

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);
});
Enter fullscreen mode Exit fullscreen mode

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');
});
Enter fullscreen mode Exit fullscreen mode

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);
});
Enter fullscreen mode Exit fullscreen mode

Visual Regression

test('homepage matches screenshot', async ({ page }) => {
  await page.goto('https://myapp.com');
  await expect(page).toHaveScreenshot('homepage.png', {
    maxDiffPixelRatio: 0.01,
  });
});
Enter fullscreen mode Exit fullscreen mode

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'] },
  ],
});
Enter fullscreen mode Exit fullscreen mode

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)