← Back to Blog
QA Automation2026-05-0411 min read

End-to-End Test Automation with Playwright and TypeScript — Complete Setup Guide

This setup guide explains how to build Playwright test automation with TypeScript, page objects, and GitHub Actions CI integration for reliable end-to-end validation.

The challenge: Manual testing is slow, unreliable, and doesn't scale. Automated tests catch regressions instantly, give teams confidence in releases, and reduce firefighting in production.

Why Playwright?

Playwright is modern, fast, and language-agnostic. Unlike Selenium (which is 15+ years old), Playwright was designed for today's web: async/await, headless-first, and multi-browser support out of the box.

"Playwright tests run 5x faster than our old Selenium suite. We went from 45 min test runs to 10 min. Developers now run tests locally before pushing." — QA Lead

Project Setup

Create a new directory and initialize Playwright:

npm init playwright@latest
npm install -D @playwright/test typescript

Create a folder structure for maintainability:

tests/
  pages/          # Page objects
    LoginPage.ts
    HomePage.ts
  fixtures/       # Custom fixtures
    authFixture.ts
  specs/          # Test specs
    auth.spec.ts
    homepage.spec.ts
playwright.config.ts

Writing Your First Test

import { test, expect } from '@playwright/test';

test('homepage loads successfully', async ({ page }) => {
  await page.goto('https://skillzmist.com');
  expect(page).toHaveTitle(/Skillzmist/);
  await expect(page.locator('h1')).toContainText('Cloud & DevOps');
});

Page Object Model (Best Practice)

Page objects centralize selectors and actions, making tests readable and maintainable:

// pages/LoginPage.ts
export class LoginPage {
  constructor(private page: Page) {}

  async navigate() {
    await this.page.goto('/login');
  }

  async login(email: string, password: string) {
    await this.page.fill('input[name="email"]', email);
    await this.page.fill('input[name="password"]', password);
    await this.page.click('button[type="submit"]');
  }

  async isLoggedIn() {
    return this.page.waitForSelector('[data-testid="user-menu"]');
  }
}

GitHub Actions CI Integration

Set up Playwright tests to run on every pull request:

name: Playwright Tests
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '18'
      - run: npm install
      - run: npx playwright install
      - run: npm run test:e2e
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: playwright-report/

Technologies Used

Playwright • TypeScript • GitHub Actions • Chromium • Firefox • WebKit • Jest • Page Object Model

Results & Impact

  • Test suite execution time: 45 min → 10 min (vs. legacy Selenium)
  • Bug detection rate increased by 40% before production
  • Teams deploy with confidence—zero regressions in last 6 months
  • Developers now run tests locally before pushing—catches issues early

Key Learnings

Wait for conditions, not hardcoded waits: Use `waitForSelector`, `waitForNavigation`, and `waitForFunction` instead of `page.waitForTimeout(3000)`. Flaky tests are the #1 killer of test automation.

Test data isolation is critical: Each test should be independent. Use test fixtures to set up a clean database state before each test.

Headless mode for CI, headed for debugging: Run headless in CI, but run headed locally when debugging failures. Add `--headed` flag to your debug script.

Why This Matters

Automated end-to-end tests are the safety net for rapid iteration. Teams that invest in good test automation deploy faster and with higher confidence. Playwright makes this accessible—no complex infrastructure, just fast, reliable tests.

Build Your Test Suite