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
Ensure test coverage