On this page14 sections
Playwright + TypeScript E2E Automation
A complete end-to-end automation project using Playwright and TypeScript, covering Page Object Model, API setup, fixture factories, and GitHub Actions CI.
Repository
View repository ↗Overview
This project demonstrates a production-style Playwright + TypeScript test suite against a demo e-commerce application (Sauce Demo — saucedemo.com). It covers the full automation lifecycle: environment setup, Page Object Model design, fixture-based test isolation, API-assisted state setup (bypassing the UI for preconditions), parallel execution, and a GitHub Actions pipeline with HTML report upload. The goal is to show the patterns that interviewers actually look for — not just working tests, but a maintainable framework you could hand to a colleague.
Project goals
- ›Implement a Page Object Model that separates locator management from test logic
- ›Use Playwright fixtures to share authenticated page state across tests without repeating login steps
- ›Set up test data via the API rather than the UI wherever possible to keep tests fast and stable
- ›Achieve parallel execution across browsers (Chromium, Firefox, WebKit) with zero test interference
- ›Generate an HTML report and publish it as a GitHub Actions artifact
- ›Keep TypeScript strict-mode enabled with no type errors
Architecture
Page Object Model with Fixture Layer
Tests are isolated from UI implementation details by a POM layer. A custom fixture file extends the base Playwright test to provide pre-authenticated pages and shared helper instances. Data factories create test objects without coupling tests to specific UI flows.
tests/— Test files (.spec.ts); contain only assertions and user-journey stepspages/— Page Object classes; own locators and page-level actionsfixtures/— Custom Playwright fixtures; extend base test with shared contextutils/— API helpers, data factories, environment configplaywright.config.ts— Browser projects, base URL, parallelism, reporter configPrerequisites
- ✓Node.js 18 or later
- ✓npm 9 or later
- ✓Git
- ✓A GitHub account (for CI pipeline)
- ✓Familiarity with TypeScript basics (interfaces, async/await)
Folder structure
playwright.config.ts # Browser projects, base URL, retry, reporter, and timeout config
.env.example # Template for environment variables — copy to .env
tests/ # All .spec.ts test files — one file per user journey
tests/auth/login.spec.ts # Login flow: happy path, wrong credentials, lockout
tests/shop/checkout.spec.ts # Add-to-cart and checkout flow with payment details
tests/shop/product-filters.spec.ts # Sort and filter behaviour on the product listing page
pages/ # Page Object Model classes
pages/LoginPage.ts # Locators and actions for the login page
pages/ProductPage.ts # Product listing interactions: sort, filter, add to cart
pages/CheckoutPage.ts # Multi-step checkout: cart → address → payment → confirmation
fixtures/ # Custom Playwright test fixtures
fixtures/auth.fixture.ts # Provides an authenticated storageState; avoids repeated login
fixtures/index.ts # Merges all custom fixtures into a single extended test export
utils/ # Shared helpers not tied to any page
utils/apiClient.ts # Thin Playwright APIRequestContext wrapper for pre-test data setup
utils/dataFactory.ts # Generates valid order and user objects for test data
utils/env.ts # Typed access to process.env with validation on startupSetup & run
Installation
- 1.
Clone the repository: git clone <repo-url> && cd playwright-typescript - 2.
Install dependencies: npm install - 3.
Install Playwright browsers: npx playwright install --with-deps - 4.
Copy environment config: cp .env.example .env - 5.
Set BASE_URL in .env (defaults to https://www.saucedemo.com) - 6.
Verify setup: npx playwright test --list
Commands
Run all tests (headless, all browsers)
npx playwright testRuns the full suite across Chromium, Firefox, and WebKit in parallel
Run tests in a single browser
npx playwright test --project=chromiumUseful during development to get faster feedback
Run a specific test file
npx playwright test tests/checkout.spec.tsRun tests in headed mode (watch the browser)
npx playwright test --headedRun tests in UI mode (interactive trace viewer)
npx playwright test --uiOpens Playwright's built-in visual test runner — great for debugging
Open last HTML report
npx playwright show-reportDebug a failing test
npx playwright test tests/login.spec.ts --debugOpens the Playwright Inspector for step-by-step debugging
Environment
| Variable | Description | Example | Required |
|---|---|---|---|
BASE_URL | Root URL of the application under test | https://www.saucedemo.com | Yes |
TEST_USER_USERNAME | Username for the standard test account | standard_user | Yes |
TEST_USER_PASSWORD | Password for the standard test account | secret_sauce | Yes |
HEADLESS | Set to 'false' to run browsers in headed mode locally | true | No |
Test data strategy
- ›Login state is captured once via the auth fixture and reused across tests using Playwright's storageState — no repeated UI logins
- ›Cart and order data is seeded via API calls in beforeAll hooks so tests start from a known state without relying on the UI
- ›The dataFactory utility generates unique email addresses using a timestamp suffix to prevent conflicts in parallel runs
- ›Sensitive credentials live in .env (gitignored); CI injects them as GitHub Actions secrets
- ›No test mutates shared data; each test either creates its own data or reads from a pre-seeded fixture
Reporting
- ›Playwright HTML Report is generated on every run; open with `npx playwright show-report`
- ›Failed tests attach a screenshot, a video, and a trace file automatically — viewable in the HTML report
- ›GitHub Actions uploads the report as a downloadable artifact on every CI run, including failures
- ›A JSON reporter is also configured to allow downstream processing (e.g. custom dashboards or Slack notifications)
CI/CD
- ›A .github/workflows/playwright.yml workflow triggers on push and pull_request events
- ›The workflow uses actions/setup-node@v4 pinned to Node 20 and caches npm dependencies
- ›Browsers are installed with `npx playwright install --with-deps chromium` (Chromium only in CI for speed)
- ›Tests run with `npx playwright test --project=chromium` to reduce CI minutes
- ›The report directory is uploaded with actions/upload-artifact@v4 so failures are debuggable without a local environment
- ›BASE_URL, TEST_USER_USERNAME, and TEST_USER_PASSWORD are passed as repository secrets
Common issues
Tests fail with 'Target closed' or 'Timeout' in parallel mode
Cause: Tests are sharing mutable state (e.g. a shared page object instance) across workers
Fix: Ensure each test creates its own page via the fixture; never share a Page object between tests
Auth fixture re-runs login on every test instead of reusing state
Cause: storageState file is not written to disk or its path is not referenced in the project config
Fix: Check that auth.fixture.ts writes storageState to a temp file and playwright.config.ts references it via `storageState` in the project options
Locators break after a page re-render (SPA navigation)
Cause: Using CSS selectors or XPath that depend on element position rather than semantic attributes
Fix: Switch to role-based locators (getByRole, getByLabel, getByTestId) which are resilient to layout changes
`npx playwright install` hangs or times out in a corporate network
Cause: Browser downloads are blocked by a proxy
Fix: Set HTTPS_PROXY and PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1, then download browsers manually via the Playwright CDN mirror
TypeScript errors on Playwright imports after upgrading
Cause: Type definitions are out of sync between @playwright/test and the installed browser binaries
Fix: Run `npm install @playwright/test@latest` and `npx playwright install` together
Best practices
- ✓Use `getByRole`, `getByLabel`, and `getByTestId` locators over CSS selectors — they match user intent and survive UI refactors
- ✓Keep Page Object classes focused: own locators and single-action methods, never assertions
- ✓Use `expect.soft` for non-critical assertions so a single field failure doesn't abort the whole test
- ✓Avoid `page.waitForTimeout`; rely on Playwright's auto-wait and `waitFor` with explicit conditions instead
- ✓Run with `--retries 1` in CI to catch intermittent network flakiness without masking real failures
- ✓Tag slow tests with `@slow` and use `test.slow()` to triple the default timeout only where needed
- ✓Keep the `playwright.config.ts` as the single source of truth for timeouts, base URL, and browser projects
Next steps
- →Add an accessibility spec using axe-playwright to catch WCAG violations on each key page
- →Extend the API helper to cover the full cart and order management API so tests can set up and tear down data without any UI interaction
- →Add visual comparison tests using `expect(page).toHaveScreenshot()` for UI-critical pages like the product listing
- →Set up a test environment in Docker so the suite can run against a locally served version of the app
- →Wire Allure Reporter as an alternative to the built-in HTML report for richer history and trend dashboards