π A Production-Grade End-to-End Testing Framework
Built with Playwright, TypeScript, and Industrial-Quality Automation
Features β’ Quick Start β’ Architecture β’ Quality Gates β’ CI/CD
|
|
|
.
βββ π§ Configuration & Setup
β βββ playwright.config.ts # Playwright configuration (browsers, timeouts, retries)
β βββ tsconfig.json # TypeScript strict mode configuration
β βββ .eslintrc.cjs # ESLint rules and plugins
β βββ .prettierrc # Prettier formatting rules
β βββ .env.example # Environment variables template
β
βββ π€ CI/CD & Automation
β βββ .github/workflows/
β β βββ ci.yml # Staged CI pipeline (install, lint, typecheck, test, publish)
β β βββ codeql.yml # Security scanning
β βββ .husky/ # Git hooks
β β βββ pre-commit # Pre-commit validation (lint-staged)
β β βββ pre-push # Pre-push quality checks
β β βββ pre-merge # Pre-merge validation
β β βββ post-merge # Post-merge smoke tests
β βββ scripts/
β β βββ git-hooks/
β β β βββ pre-commit.ps1 # PowerShell pre-commit script
β β β βββ pre-commit.sh # Bash pre-commit script
β β βββ post-pull-checks.ps1 # Environment verification script
β β βββ post-pull-checks.sh # Bash environment check
β βββ Dockerfile & docker-compose.yml
β
βββ π Source Code
β βββ src/
β β βββ pages/ # Page Object classes
β β β βββ BasePage.ts # Abstract base with common methods
β β β βββ LoginPage.ts # Example page objects
β β β βββ DashboardPage.ts
β β β βββ infrastructure/
β β β βββ PageFactory.ts # Dynamic page object factory
β β β βββ index.ts
β β β
β β βββ interface/ # TypeScript contracts
β β β βββ pages.interface.ts # ILoginPage, IDashboardPage, etc.
β β β βββ api.interface.ts # API request/response types
β β β
β β βββ utils/ # Utility functions
β β β βββ apiHelper.ts # Type-safe API client
β β β βββ schemaValidator.ts # JSON schema validation (AJV)
β β β βββ selectors.ts # Centralized selector definitions
β β β βββ assertions.ts # Custom assertions
β β β βββ logger.ts # Logging utilities
β β β βββ [other utilities]
β β β
β β βββ core/ # Core framework
β β β βββ base/BasePage.ts # Base page object class
β β β βββ fixtures/ # Playwright fixtures
β β β βββ utils/ # Core utilities
β β β
β β βββ fixture/ # Test data & fixtures
β β β βββ auth.fixture.ts # Authentication fixture
β β β βββ README.md
β β β
β β βββ config/ # Application configurations
β β βββ app.config.ts # App registry and settings
β β βββ [app-specific configs]
β β
β βββ tests/ # Test suites
β β βββ cura/ # CURA suites (auth, smoke, regression, a11y, performance)
β β βββ orangehrm/ # OrangeHRM suites
β β βββ saucedemo/ # SauceDemo suites
β β βββ shared/ # Shared auth and API coverage
β β βββ templates/ # Numbered template track (01-10)
β β
β βββ test-data/ # Test data files
β β βββ fixtures/ # Shared test data (JSON)
β β βββ dev/ # Development environment data
β β βββ qa/ # QA environment data
β β
β βββ schemas/ # JSON Schema definitions
β β βββ user.schema.json # User response schema
β β βββ error.schema.json # Error response schema
β β βββ createUser.request.schema.json
β β
β βββ globals/ # Global test setup/teardown
β β βββ global-setup.ts # Global authentication setup
β β βββ global-teardown.ts # Cleanup operations
β β
β βββ storage-state/ # Saved browser authentication state
β
βββ π Reports & Results
β βββ playwright-report/ # HTML test report (interactive)
β βββ test-results/ # JSON test results
β βββ screenshots/ # Failure screenshots
β
βββ π Documentation
β βββ docs/
β β βββ FRAMEWORK_INDEX.md # Current framework overview
β β βββ FRAMEWORK_IMPLEMENTATION.md # Implementation guide
β β βββ PRODUCTION_FRAMEWORK_SUMMARY.md
β β βββ STRUCTURE_REFACTORING.md # Structure history and migration notes
β β βββ PRODUCTION_READINESS.md # Production checklist
β β βββ CONTRIBUTING.md # Development guidelines
β β βββ SECURITY.md # Security guidelines
β
βββ π¦ Dependencies & Configuration
βββ package.json
βββ package-lock.json
βββ .gitignore
βββ README.md (this file)
- Node.js 20+
- npm 10+
- Git
# Clone the repository
git clone https://github.com/prasad291024/playwright-automation-framework.git
cd playwright-automation-framework
# Install dependencies
npm install
# Install Playwright browsers
npx playwright install
# Verify environment
npm run verify-envCreate a .env file in the project root:
# Application Configuration
BASE_URL=https://your-app-url.com
APP_NAME=local # or: saucedemo, cura, orangehrm
# Authentication
USERNAME=your_username
PASSWORD=your_password
# Logging
LOG_LEVEL=info # debug, info, warn, error
# Timeouts (milliseconds)
ACTION_TIMEOUT=5000
NAVIGATION_TIMEOUT=30000# Run all tests (headless)
npm test
# Run smoke tests only (@smoke tag)
npm run test:smoke
# Run with visible browser
npm run test:headed
# Run specific active test file
npx playwright test tests/saucedemo/smoke/login.spec.ts
# Run tests matching pattern
npx playwright test --grep "login"
# Debug a specific test
npx playwright test tests/auth.spec.ts --debug
# View HTML report
npx playwright show-reportTypeScript interfaces enforce contracts for page objects:
// Interface (contract)
export interface ILoginPage {
navigate(): Promise<void>;
fillUsername(username: string): Promise<void>;
clickLoginButton(): Promise<void>;
getErrorMessage(): Promise<string>;
}
// Implementation
export class LoginPage extends BasePage implements ILoginPage {
async navigate(): Promise<void> {
await this.goto('/login');
await this.waitForPageLoad();
}
async fillUsername(username: string): Promise<void> {
await this.getByTestId('username-input').fill(username);
}
async clickLoginButton(): Promise<void> {
await this.getByRole('button', { name: /sign in/i }).click();
}
}-
Test ID β
data-testid(explicit, maintainable)await this.getByTestId('submit-button').click();
-
Role-based β
getByRole(accessible, semantic)await this.getByRole('button', { name: /login/i }).click();
-
Text/Placeholder β User-centric selectors
await this.getByText('Submit').click();
-
CSS/XPath β Last resort only (fragile, avoid when possible)
All page objects inherit from BasePage for unified locator strategies:
export abstract class BasePage {
constructor(protected page: Page) {}
// Role-based selectors (preferred for accessibility)
protected getByRole(role: AriaRole, options?: GetByRoleOptions) {
return this.page.getByRole(role, options);
}
// Test ID selectors (explicit, maintainable)
protected getByTestId(testId: string) {
return this.page.getByTestId(testId);
}
// Navigation helpers
async goto(path: string) { ... }
async navigateTo(url: string) { ... }
async waitForPageLoad() { ... }
// Common assertions
async waitForElement(selector: string) { ... }
async isElementVisible(locator: Locator) { ... }
}import { apiHelper } from '../src/utils/apiHelper';
// Automatically validates response against user.schema.json
const user = await apiHelper.getUser(1);
console.log(user.id, user.name, user.email);
// Create user with automatic validation
const newUser = await apiHelper.createUser({
name: 'John Doe',
email: 'john@example.com',
phone: '555-1234',
});
// Validation error handling
try {
const response = await apiHelper.getUser(999);
} catch (error) {
console.error('API Error or validation failed:', error.message);
}import { schemaValidator } from '../src/utils/schemaValidator';
// Validate data against schema
const result = schemaValidator.validate(userData, 'user.schema.json');
if (!result.isValid) {
console.error('Validation errors:', result.errors);
}
// Validate or throw
schemaValidator.validateOrThrow(response, 'user.schema.json');
// Get human-readable errors
const messages = schemaValidator.getErrorMessages('user.schema.json', data);
messages.forEach((msg) => console.log(msg));This framework implements four control points in the development lifecycle to ensure production-ready automation code.
Purpose: Prevent bad code from entering the repository
Trigger: Automatic on git commit
Technology: Husky + lint-staged
Checks:
- β ESLint validation with auto-fix
- β Prettier formatting with auto-fix
- β
TypeScript compilation (manual:
npm run typecheck)
# Automatic on every commit
git commit -m "feat: my changes"
# β Husky runs ESLint + Prettier automatically
# β Commit succeeds if all checks pass
# β Commit fails if checks cannot be auto-fixedFiles Modified:
.husky/pre-commitβ Runsnpx lint-stagedscripts/git-hooks/pre-commit.ps1&.shβ Alternative implementation
Purpose: Verify developer environment consistency after repository updates
Trigger: Manual execution after git pull
Command: npm run verify-env
Checks:
- β Dependencies installation
- β Browser installation
- β Code quality validation
- β Smoke test execution (@smoke)
# After pulling new changes
git pull
npm run verify-env
# β Installs dependencies
# β Installs browsers
# β Runs linting and type checking
# β Executes smoke test suiteImplementation:
scripts/post-pull-checks.ps1β PowerShell versionscripts/post-pull-checks.shβ Bash version- Package.json script:
"verify-env"
Purpose: Validate code meets standards before merge to main
Trigger: Pull Request to main branch
Technology: GitHub Actions
Workflow: .github/workflows/ci.yml
Checks:
- β Install Dependencies β workspace/bootstrap stage
- β Lint β ESLint + Prettier validation
- β Type check β TypeScript compilation
- β Code Quality Checks β staged quality gate summary
- β Test β smoke scope on PR, broader suite coverage on push/manual runs
- β Publish Report β artifact and report summary stage
Each job appears as individual status check:
Install DependenciesβLintβType checkβCode Quality ChecksβTestβPublish Reportβ
# Jobs run in stages after dependency installation
jobs:
install:
runs-on: ubuntu-latest
lint:
runs-on: ubuntu-latest
needs: install
typecheck:
runs-on: ubuntu-latest
needs: install
code_quality:
runs-on: ubuntu-latest
needs: [lint, typecheck]
test:
runs-on: ubuntu-latest
needs: [install, code_quality]
publish_report:
runs-on: ubuntu-latest
needs: [install, test]Purpose: Ensure main branch remains production-ready
Trigger: Push to main branch after merge
Workflow: .github/workflows/ci.yml
Checks:
- β
Staged CI execution on
main - β Smoke/full scope selection based on event type
- β HTML, JSON, JUnit, and raw artifact upload
- β Published CI run summary
Tests are tagged for selective execution across the pipeline:
| Tag | Purpose | When to Use |
|---|---|---|
@smoke |
Core health checks, fast execution | PR validation, smoke testing |
@regression |
Full feature coverage | Post-merge validation, nightly runs |
@critical |
High-risk business flows | Production-critical tests |
@performance |
Performance benchmarks | Performance testing pipeline |
@accessibility |
A11y compliance checks | Accessibility testing |
@visual |
Visual regression tests | Visual regression pipeline |
// Smoke test (runs in PR validation)
test('@smoke - user can login', async ({ page }) => {
// Test implementation
});
// Regression test (runs on main branch)
test('@regression - user can update profile', async ({ page }) => {
// Test implementation
});
// Critical path test
test('@critical - payment processing', async ({ page }) => {
// Test implementation
});# Run only smoke tests
npx playwright test --grep @smoke
# Run regression tests
npx playwright test --grep @regression
# Run critical tests
npx playwright test --grep @critical
# Run all except smoke
npx playwright test --grep --invert @smokeThe framework includes built-in strategies to reduce flakiness:
// playwright.config.ts
export default defineConfig({
// Retry failed tests in CI, not locally
retries: process.env.CI ? 2 : 0,
// Detailed diagnostics on first retry
trace: 'on-first-retry',
video: 'retain-on-failure',
screenshot: 'only-on-failure',
});// Always wait for ready state
await page.goto(url, { waitUntil: 'networkidle' });
// Use Playwright's built-in waits
await page.waitForLoadState('networkidle');
await page.waitForSelector('.loaded', { timeout: 10000 });// Playwright auto-waits for assertions
await expect(element).toBeVisible(); // Waits up to 5s
await expect(element).toHaveText('Expected text'); // Auto-waitsnpx playwright show-reportLocation: playwright-report/index.html
Shows:
- β Test execution timeline
- β Pass/fail breakdown
- β Screenshots of failures
- β Video playback
- β Execution traces for debugging
Location: test-results/results.json
Use for:
- CI/CD integration
- Dashboards
- Custom analytics
Automatically captured for failed tests:
- πΈ Screenshots
- π₯ Video recordings
- π Execution traces
- π Network logs
Configure the following in GitHub repository settings to protect the main branch:
β Require status checks to pass before merging
LintType checkUnit / smoke tests
β Require branches to be up to date before merging
β Require pull request reviews before merging
- Minimum: 1 approval
β Require conversation resolution before merging
β Require linear history
β Block force pushes
β Restrict who can push to matching branches
- Go to: Settings β Branches
- Click "Add rule"
- Branch name pattern:
main - Enable protections above
- Click "Create"
See Framework Index and Contributing for current workflow guidance.
| Command | Purpose |
|---|---|
npm test |
Run all tests (headless) |
npm run test:headed |
Run with visible browser |
npm run test:debug |
Debug mode with inspector |
npm run test:ui |
Interactive UI mode |
npm run test:smoke |
Run @smoke tests only |
npm run lint |
Check code style |
npm run lint:fix |
Auto-fix linting issues |
npm run format |
Format code |
npm run format:check |
Check formatting |
npm run typecheck |
Validate TypeScript |
npm run verify-env |
Verify environment health |
npm run pre-pull |
Pre-pull checks |
npm run pre-merge |
Pre-merge checks |
npm run pre-push |
Pre-push checks |
# Run tests in Docker
docker-compose up test
# Run specific browser
docker-compose up test -- --project=firefox
# Run with headed browser
docker-compose run --build test-headed
# Build image
docker-compose build# Build image
docker build -t playwright-tests .
# Run tests
docker run --rm \
-v $(pwd)/test-results:/app/test-results \
-v $(pwd)/playwright-report:/app/playwright-report \
playwright-testsimport { test, expect } from '@playwright/test';
import { LoginPage } from '../src/pages/LoginPage';
import { DashboardPage } from '../src/pages/DashboardPage';
test.describe('User Authentication @smoke', () => {
let loginPage: LoginPage;
let dashboardPage: DashboardPage;
test.beforeEach(async ({ page }) => {
loginPage = new LoginPage(page);
dashboardPage = new DashboardPage(page);
});
test('should login with valid credentials', async () => {
// Arrange
const testUser = {
username: 'test@example.com',
password: 'SecurePassword123',
};
// Act
await loginPage.navigate();
await loginPage.fillUsername(testUser.username);
await loginPage.fillPassword(testUser.password);
await loginPage.clickLoginButton();
// Assert
await expect(dashboardPage.getWelcomeMessage()).toContainText(`Welcome, ${testUser.username}`);
});
test('should display error with invalid credentials', async () => {
// Act
await loginPage.navigate();
await loginPage.fillUsername('invalid@example.com');
await loginPage.fillPassword('wrong');
await loginPage.clickLoginButton();
// Assert
await expect(loginPage.getErrorMessage()).toBeVisible();
});
test('should require username and password', async () => {
// Act
await loginPage.navigate();
await loginPage.clickLoginButton();
// Assert
await expect(loginPage.getUsernameError()).toContainText('Username is required');
});
});Comprehensive guides available in docs/:
| Document | Purpose |
|---|---|
| FRAMEWORK_INDEX.md | Current framework overview |
| TEST_STRATEGY.md | Active suite ownership and CI scope |
| FRAMEWORK_IMPLEMENTATION.md | Implementation details |
| PRODUCTION_FRAMEWORK_SUMMARY.md | Architecture summary |
| STRUCTURE_REFACTORING.md | Structure changes and migration notes |
| PRODUCTION_READINESS.md | Production checklist |
| CONTRIBUTING.md | Development guidelines |
| SECURITY.md | Security guidance |
| tests/README.md | Current active and template suites |
We follow strict quality and contribution guidelines.
-
Sync and verify environment
git pull npm run verify-env
-
Create feature branch
git checkout -b feature/your-feature-name
-
Develop and test
npm test # Run tests locally
-
Commit with pre-commit hooks
git add . git commit -m "feat: your feature" # β Pre-commit hooks run automatically
-
Push feature branch
git push origin feature/your-feature-name
-
Create Pull Request
- PR validation runs automatically
- Must pass all checks: Lint, Type check, Smoke tests
-
Merge to main
- Requires 1 approval
- All status checks must pass
- Post-merge regression suite runs
See CONTRIBUTING.md for detailed guidelines.
- Playwright Documentation
- Page Object Model
- TypeScript Handbook
- AJV JSON Schema Validator
- ESLint Rules
- Prettier Code Formatter
- GitHub Actions
- Docker Documentation
- β Review FRAMEWORK_INDEX.md for the current framework map
- β Check CONTRIBUTING.md for development guidelines
- β Explore tests/README.md for active suite organization
- β Read PRODUCTION_READINESS.md before production deployment
ISC
Made with β€οΈ by Prasad β Test Automation Engineer
β Star on GitHub if you find this useful!
Create a .env file in the project root:
BASE_URL=https://your-app-url.com
USERNAME=your_username
PASSWORD=your_password
LOG_LEVEL=info# Run all tests (headless)
npm test
# Run tests with visible browser
npm run test:headed
# Run specific test file
npx playwright test tests/auth.api.spec.ts
# Run tests matching pattern
npx playwright test --grep "login"
# View HTML report
npx playwright show-reportThis framework uses a modern POM pattern with TypeScript interfaces:
// Interface contract
export interface ILoginPage {
navigate(): Promise<void>;
fillUsername(username: string): Promise<void>;
fillPassword(password: string): Promise<void>;
clickLoginButton(): Promise<void>;
}
// Implementation extending BasePage
export class LoginPage extends BasePage implements ILoginPage {
async navigate(): Promise<void> {
await this.goto('/login');
await this.waitForPageLoad();
}
async fillUsername(username: string): Promise<void> {
// Prefer testId over CSS selectors
await this.getByTestId(SELECTORS_BY_TESTID.login.usernameInput).fill(username);
}
// ... more methods
}All page objects inherit from BasePage, providing unified locator strategies:
export abstract class BasePage {
// Preferred: Role-based selectors (accessible, resilient)
protected getByRole(role: AriaRole, options?: GetByRoleOptions) {}
// Preferred: Test ID selectors (explicit data-testid attributes)
protected getByTestId(testId: string) {}
// Navigation helpers
async goto(path: string) {}
async navigateTo(url: string) {}
async waitForPageLoad() {}
}- Test ID β
data-testidattributes (explicit, maintainable) - Role-based β
getByRole('button', { name: /label/i })(accessible) - Text/Placeholder β
getByText(),getByPlaceholder()(user-centric) - CSS/XPath β Last resort only (brittle, avoid)
import { apiHelper } from '../src/utils/apiHelper';
// Automatically validates response against user.schema.json
const user = await apiHelper.getUser(1);
// Create user with type validation
const newUser = await apiHelper.createUser({
name: 'John Doe',
email: 'john@example.com',
phone: '555-1234',
});
// Error handling with schema validation
try {
const response = await apiHelper.getUser(999);
} catch (error) {
console.error('Validation failed:', error.message);
}import { schemaValidator } from '../src/utils/schemaValidator';
// Validate against schema
const result = schemaValidator.validate(userData, 'user.schema.json');
if (!result.valid) {
console.error('Validation errors:', result.errors);
}
// Throw on validation failure
schemaValidator.validateOrThrow(response, 'user.schema.json');
// Get human-readable error messages
const messages = schemaValidator.getErrorMessages('user.schema.json', data);# Check code style
npm run lint
# Auto-fix linting issues
npm run lint:fix
# Format code
npm run format
# Validate TypeScript
npm run typecheckAutomatically runs on every git commit:
- ESLint checks and fixes
*.tsfiles - Prettier formats code
- Commit rejected if checks fail
No manual intervention neededβhooks run automatically.
Runs on every push and pull request:
- Browsers: Chromium, Firefox, WebKit
- Platforms: Ubuntu, Windows, macOS
- Quality: ESLint, Prettier, TypeScript checks
- Reports: HTML + JSON artifacts
# View workflows
.github/workflows/ci.yml # Main staged CI pipeline
.github/workflows/codeql.yml # Security scanning# Run tests in Docker
docker-compose up test
# Run with headed browser
docker-compose --profile headed up test-headed
# Build image
docker-compose build# Build image
docker build -t playwright-tests .
# Run tests
docker run --rm \
-v $(pwd)/test-results:/app/test-results \
-v $(pwd)/playwright-report:/app/playwright-report \
playwright-tests
# Run specific browser
docker run --rm playwright-tests npm test -- --project=firefox| Script | Purpose |
|---|---|
npm test |
Run all tests (headless) |
npm run test:headed |
Run tests with visible browser |
npm run lint |
Check code style |
npm run lint:fix |
Auto-fix linting errors |
npm run format |
Format code with Prettier |
npm run typecheck |
Validate TypeScript |
- HTML Report:
playwright-report/index.htmlβ Interactive test results - JSON Report:
test-results/results.jsonβ Machine-readable results - Screenshots:
screenshots/β Failure screenshots - Videos: Captured for failed tests (configurable)
# View HTML report
npx playwright show-reportimport { test, expect } from '@playwright/test';
import { LoginPage } from '../src/pages/LoginPage';
import { DashboardPage } from '../src/pages/DashboardPage';
test.describe('User Authentication Flow', () => {
let loginPage: LoginPage;
let dashboardPage: DashboardPage;
test.beforeEach(async ({ page }) => {
loginPage = new LoginPage(page);
dashboardPage = new DashboardPage(page);
await loginPage.navigate();
});
test('should login with valid credentials', async () => {
// Arrange
const testUser = {
username: 'user@example.com',
password: 'SecurePassword123',
};
// Act
await loginPage.fillUsername(testUser.username);
await loginPage.fillPassword(testUser.password);
await loginPage.clickLoginButton();
// Assert
await expect(dashboardPage.getWelcomeMessage()).toContainText('Welcome');
});
test('should reject invalid credentials', async () => {
// Act
await loginPage.fillUsername('invalid@example.com');
await loginPage.fillPassword('wrong');
await loginPage.clickLoginButton();
// Assert
await expect(loginPage.getErrorMessage()).toBeVisible();
});
});See CONTRIBUTING.md for:
- Development setup
- Git workflow and commit conventions
- Testing guidelines
- Code style requirements
- Pull request process
- Playwright Documentation
- Page Object Model Best Practices
- TypeScript Handbook
- AJV JSON Schema Validator
- ESLint Rules
- Prettier Formatting
- GitHub Actions Documentation
Developed by Prasad β Software Test Engineer, passionate about test automation, framework design, and engineering excellence.
ISC
Ready to contribute? See CONTRIBUTING.md for guidelines!