Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ jobs:
- name: Checkout repo
uses: actions/checkout@v3

- name: Cache node_modules
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-

- name: Build Docker Image
run: docker build -t my-playwright-runner -f Dockerfile.playwright .

Expand Down Expand Up @@ -79,4 +87,4 @@ jobs:
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./allure-report
publish_branch: gh-pages
publish_branch: gh-pages
44 changes: 31 additions & 13 deletions Dockerfile.playwright
Original file line number Diff line number Diff line change
@@ -1,30 +1,48 @@
FROM mcr.microsoft.com/playwright:v1.53.1-jammy
# ---- Build Stage ----
FROM mcr.microsoft.com/playwright:v1.53.1-jammy AS build

# Install Java 11 (required for Allure)
# Install Java 11 (for Allure)
RUN apt-get update && apt-get install -y wget gnupg2 && \
wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor -o /usr/share/keyrings/adoptium.gpg && \
echo "deb [signed-by=/usr/share/keyrings/adoptium.gpg] https://packages.adoptium.net/artifactory/deb focal main" | tee /etc/apt/sources.list.d/adoptium.list && \
apt-get update && apt-get install -y temurin-11-jdk && \
rm -rf /var/lib/apt/lists/*

# Install Allure CLI globally
RUN npm install -g allure-commandline --force

# Set JAVA_HOME for Allure
ENV JAVA_HOME=/usr/lib/jvm/temurin-11-jdk-amd64
ENV PATH=$JAVA_HOME/bin:$PATH

# Set working directory
WORKDIR /app

# Copy only package files first to cache layer
# Copy package files first to leverage Docker caching
COPY package*.json ./

# Install Node dependencies
RUN npm ci

# Copy the rest of the application
# Copy environment files
COPY env ./env

# Copy the full application
COPY . .

# Default CMD is overridden by GitHub Action's docker run step
# ---- Final Stage ----
FROM mcr.microsoft.com/playwright:v1.53.1-jammy

# Install Java 11 and Allure CLI
RUN apt-get update && apt-get install -y wget gnupg2 && \
wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor -o /usr/share/keyrings/adoptium.gpg && \
echo "deb [signed-by=/usr/share/keyrings/adoptium.gpg] https://packages.adoptium.net/artifactory/deb focal main" | tee /etc/apt/sources.list.d/adoptium.list && \
apt-get update && apt-get install -y temurin-11-jdk && \
npm install -g allure-commandline --force && \
rm -rf /var/lib/apt/lists/*

ENV JAVA_HOME=/usr/lib/jvm/temurin-11-jdk-amd64
ENV PATH=$JAVA_HOME/bin:$PATH

WORKDIR /app

# Copy built assets and node_modules from the build stage
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/env ./env
COPY --from=build /app/. .
COPY --from=build /app/package*.json ./

# Default CMD — runs Playwright tests and generates Allure report
CMD ["npm", "run", "test:allure"]
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Supports cross-browser testing, rich reporting with **Allure**, Dockerized execu

## 📚 Documentation

- [ARCHITECTURE](docs/ARCHITECTURE.md)
- [BasePage](docs/BasePage.md)
- [LoginPage](docs/LoginPage.md)
- [HomePage](docs/HomePage.md)
Expand Down Expand Up @@ -96,7 +97,20 @@ e2e-playwright-framework/
├── DockerFile.playwright # Dockerfile for CI/CD
├── .github/workflows/ # GitHub Actions workflows
```
## 🌐 Overriding baseURL

- By default, `baseURL` is loaded from your environment file (e.g., `env/.env.dev1`).
- To override for a specific run, set the `BASE_URL` variable:

```sh
BASE_URL=https://another-url.com npm test
```

- Or use a different environment:

```sh
TEST_ENV=dev1 npm test
```
---

## ✅ GitHub Actions CI/CD
Expand Down Expand Up @@ -148,6 +162,8 @@ This project uses **GitHub Actions** to automate test execution and reporting.

---



## 📄 License

MIT © 2025 Ramakrishna Jangatisetty
141 changes: 141 additions & 0 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# 📘 Playwright E2E Framework - Architecture Documentation

## 📁 Project Structure Overview

```
├── .github/workflows/
│ └── playwright.yml # GitHub Actions workflow with dynamic test config
├── env/
│ └── .env.qa1 # Environment-specific config
├── global/
│ ├── setup.ts # Global setup for context and metadata
│ ├── teardown.ts # Global teardown to enrich test results
├── pages/
│ ├── BasePage.ts # Base class with reusable Playwright actions
│ └── LoginPage.ts # Page Object Model (POM) for Login page
├── playwright-report/ # Allure and JSON report outputs
├── tests/
│ ├── testsetup.ts # Custom test hooks with logger integration
│ └── ui/
│ └── login.spec.ts # Sample test for login validation
├── utils/
│ ├── allureHelper.ts # Helper for tagging tests in Allure
│ ├── config.ts # Typed environment config reader
│ ├── loadEnv.ts # Dynamic .env loader by TEST_ENV
│ └── logger.ts # Winston logger
├── Dockerfile.playwright # Multi-stage Dockerfile with Java + Allure setup
├── package.json
├── playwright.config.ts # Main test runner config
└── run-with-params.sh # Shell script for running tests with dynamic env
```

---

## 🔧 Core Technologies

* **Playwright** for browser automation
* **TypeScript** for type safety and maintainability
* **Allure Reporter** for rich test visualization
* **Docker** to encapsulate execution
* **GitHub Actions** for CI/CD with test param flexibility

---

## 🏗️ Key Components Explained

### ✅ playwright.config.ts

* Configures base test settings, retries, reporters, and project runners.
* Includes:

* Global hooks (`globalSetup`, `globalTeardown`)
* `json` reporter for enriching data in teardown
* Allure and HTML reports

### ✅ global/setup.ts

* Loads environment from `.env.{env}` using `loadEnv.ts`
* Initializes metadata like testRunId, startTime
* Writes `test-run-context.json`

### ✅ global/teardown.ts

* Parses `test-results.json`
* Enhances each test case with:

* Duration, tags, retry count
* Failure message + stack trace if applicable
* History stub fields (e.g., flaky count, last failed)
* Merges data into `enriched-test-results.json`

### ✅ testsetup.ts

* Adds `beforeEach` and `afterEach` logging using Winston
* Replaces Playwright's default test

### ✅ Dockerfile.playwright

* Multi-stage:

* Stage 1 installs deps and caches builds
* Stage 2 copies node\_modules, env, and source
* Includes Java and Allure CLI for reporting

### ✅ GitHub Actions Workflow

* Supports inputs: `tag`, `browser`, `workers`, `retries`, `test_env`
* Uses `run-with-params.sh` inside container
* Publishes Allure report to GitHub Pages

### ✅ env/.env.qa1

* Customizes:

* `URL=https://saucedemo.com`
* `USERNAME`, `PASSWORD`

### ✅ utils/config.ts

* Loads env vars with type safety
* Validates missing values early

### ✅ utils/logger.ts

* Uses Winston logger with ISO timestamps

### ✅ run-with-params.sh

* Dynamically runs Playwright with flags like:

```bash
npx playwright test \
--project="$BROWSER" \
--workers="$WORKERS" \
--retries="$RETRIES" \
$TAG
```

---

## 📈 Future-Ready Features (Planned or Extendable)

* 🔍 Store enriched JSON to DynamoDB/Postgres
* 📊 Build custom dashboards from enriched test result metadata
* 📤 Slack/GitHub notification integration
* 🤖 Integrate GPT-based RCA suggestions per failure
* 🔄 Automatic test rerun for flaky failures

---

## 🙌 Usage Summary

* `TEST_ENV=qa1 npx playwright test` (local)
* `docker build -t my-playwright-runner .`
* `docker run --rm -e TEST_ENV=qa1 my-playwright-runner`
* CI: Trigger via GitHub Actions with tag and env

---

## ✅ Author

Maintained by [@ramjangatisetty](https://github.com/ramjangatisetty) with ❤️ for the testing community.
2 changes: 1 addition & 1 deletion env/.env.dev1
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
URL=https://saucedemo.com
BASE_URL=https://saucedemo.com
USERNAME=standard_user
PASSWORD=secret_sauce
2 changes: 1 addition & 1 deletion env/.env.dev2
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
URL=https://saucedemo.com
BASE_URL=https://saucedemo.com
USERNAME=standard_user
PASSWORD=secret_sauce
2 changes: 1 addition & 1 deletion env/.env.qa1
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
URL=https://saucedemo.com
BASE_URL=https://saucedemo.com
USERNAME=standard_user
PASSWORD=secret_sauce
2 changes: 1 addition & 1 deletion env/.env.qa2
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
URL=https://saucedemo.com
BASE_URL=https://saucedemo.com
USERNAME=standard_user
PASSWORD=secret_sauce
4 changes: 2 additions & 2 deletions global/test-run-context.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"testRunId": "run_20250628182021939",
"startTime": "2025-06-28T18:20:21.939Z",
"testRunId": "run_20250628215003653",
"startTime": "2025-06-28T21:50:03.653Z",
"environment": "qa1",
"project": "e2e-playwright-typescript-framework",
"status": "in-progress"
Expand Down
2 changes: 1 addition & 1 deletion pages/LoginPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class LoginPage extends BasePage {
}

async goto() {
await this.page.goto(config.url)
await this.page.goto(config.baseUrl)
}

constructor(page: Page) {
Expand Down
13 changes: 11 additions & 2 deletions playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { defineConfig } from '@playwright/test';
import * as dotenvFlow from 'dotenv-flow';
import path from 'path';

// Load env variables before config is defined
dotenvFlow.config({
path: path.resolve(__dirname, 'env'),
node_env: process.env.TEST_ENV || 'local'
});

export default defineConfig({
testDir: './tests',
workers: 2,
Expand All @@ -19,9 +26,11 @@ export default defineConfig({
trace: 'on-first-retry',
},
projects: [
{ name: 'Chromium', use: { browserName: 'chromium' } }
{ name: 'Chromium', use: { browserName: 'chromium' } },
{ name: 'Firefox', use: { browserName: 'firefox' } },
{ name: 'WebKit', use: { browserName: 'webkit' } }
],

globalSetup: require.resolve('./global/setup.ts'),
globalTeardown: require.resolve('./global/teardown.ts'),
});
});
29 changes: 22 additions & 7 deletions tests/setup.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
import { test as base, expect, type Page, type TestInfo } from '@playwright/test';
import { logger } from '../utils/logger';
/**
* Custom Playwright test setup.
*
* This file exports a customized `test` and `expect` for use in all test files.
* It wraps Playwright's base test to add common hooks, logging, and shared fixtures.
*
* Usage:
* Import `test` and `expect` from this file in your test specs using a relative path:
* import { test, expect } from '../setup';
*
* Why not use a path alias?
* Playwright and Node.js do not resolve TypeScript path aliases at runtime by default.
* Using relative imports ensures compatibility in all environments.
*
* Contributors:
* - Add shared hooks, fixtures, or logging here to apply them across all tests.
* - Do not import `@playwright/test` directly in your test files—use this setup instead.
*/

base.beforeEach(async ({ page }, testInfo) => {
logger.info(`🚀 Starting test: ${testInfo.title}`);
logger.info(`🔖 Tags: ${testInfo.annotations.map(a => a.type).join(', ') || 'None'}`);
});
import { test as base, expect } from '@playwright/test';
import { logger } from '../utils/logger';

// Example: Add a global afterEach hook for logging
base.afterEach(async ({ page }, testInfo) => {
const status = testInfo.status?.toUpperCase();
const duration = `${testInfo.duration}ms`;
Expand All @@ -20,4 +35,4 @@ base.afterEach(async ({ page }, testInfo) => {
});

export const test = base;
export { expect };
export { expect };
Loading
Loading