A comprehensive, enterprise-grade test automation framework built with Java, Selenium WebDriver, TestNG, and REST Assured. This framework supports both UI and API testing with robust reporting, CI/CD integration, and best practices implementation.
- Features
- Technology Stack
- Project Structure
- Prerequisites
- Installation & Setup
- Configuration
- Running Tests
- JSON Locator System
- Page Object Model
- API Testing
- Reporting
- Screenshots
- Browser Attachment Mode
- Email Notifications
- CI/CD Integration
- Allure Report Installation
- Best Practices
- Troubleshooting
- Contributing
- ✅ Selenium WebDriver 4.x - Latest Selenium with modern browser support
- ✅ TestNG - Powerful test framework with parallel execution
- ✅ REST Assured - Comprehensive API testing capabilities
- ✅ Page Object Model (POM) - Clean, maintainable test architecture
- ✅ JSON-based Locators - Simplified, externalized element locators
- ✅ Multiple Browsers - Chrome, Firefox, Edge, Safari support
- ✅ Headless Mode - Run tests without GUI
- ✅ Parallel Execution - Run tests concurrently for faster execution
- ✅ Allure Reports - Beautiful, detailed test reports
- ✅ Extent Reports - Alternative HTML reporting
- ✅ Screenshot Capture - Automatic screenshots on failure
- ✅ Retry Mechanism - Automatic retry for flaky tests
- ✅ Environment Configuration - Secure, environment-based settings
- ✅ Browser Attachment - Reuse browser sessions for faster debugging
- ✅ Email Notifications - Send test reports via email
- ✅ CI/CD Ready - GitHub Actions, Jenkins, Azure DevOps, AWS support
- ✅ Logging - Comprehensive logging with Log4j2
| Technology | Version | Purpose |
|---|---|---|
| Java | 11+ | Programming Language |
| Maven | 3.8+ | Build & Dependency Management |
| Selenium WebDriver | 4.15.0 | Browser Automation |
| TestNG | 7.8.0 | Test Framework |
| REST Assured | 5.3.2 | API Testing |
| WebDriverManager | 5.6.2 | Automatic Driver Management |
| Allure | 2.24.0 | Test Reporting |
| Extent Reports | 5.1.1 | HTML Reporting |
| Log4j2 | 2.21.1 | Logging |
| Jackson | 2.15.3 | JSON Processing |
| AssertJ | 3.24.2 | Fluent Assertions |
Java-Selenium-Automation-Framework/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/automation/
│ │ │ ├── api/ # API testing classes
│ │ │ │ ├── ApiClient.java # REST API client
│ │ │ │ └── BaseApiTest.java # Base class for API tests
│ │ │ ├── base/ # Base classes
│ │ │ │ ├── BasePage.java # Base page object
│ │ │ │ └── BaseTest.java # Base test class
│ │ │ ├── config/ # Configuration management
│ │ │ │ └── ConfigManager.java # Configuration handler
│ │ │ ├── driver/ # WebDriver management
│ │ │ │ └── DriverManager.java # Driver factory
│ │ │ ├── listeners/ # TestNG listeners
│ │ │ │ ├── TestListener.java # Test execution listener
│ │ │ │ └── RetryAnalyzer.java # Retry failed tests
│ │ │ ├── locators/ # Locator management
│ │ │ │ └── LocatorManager.java # JSON locator parser
│ │ │ ├── pages/ # Page objects
│ │ │ │ ├── LoginPage.java # Login page object
│ │ │ │ └── HomePage.java # Home page object
│ │ │ ├── reports/ # Reporting utilities
│ │ │ │ └── ExtentReportManager.java
│ │ │ └── utils/ # Utility classes
│ │ │ ├── WaitUtils.java # Wait utilities
│ │ │ ├── ScreenshotUtils.java# Screenshot utilities
│ │ │ └── EmailUtils.java # Email utilities
│ │ └── resources/
│ │ ├── config/ # Configuration files
│ │ │ ├── config.properties # Default configuration
│ │ │ └── env.properties.template # Environment template
│ │ ├── locators/ # JSON locator files
│ │ │ ├── login-page.json # Login page locators
│ │ │ └── home-page.json # Home page locators
│ │ ├── log4j2.xml # Logging configuration
│ │ └── allure.properties # Allure configuration
│ └── test/
│ ├── java/
│ │ └── com/automation/tests/
│ │ ├── LoginTest.java # Login test cases
│ │ └── api/
│ │ └── SampleApiTest.java # API test cases
│ └── resources/
│ └── testng-suites/ # TestNG suite files
│ ├── testng.xml # All tests
│ ├── smoke-tests.xml # Smoke tests
│ ├── regression-tests.xml # Regression tests
│ └── api-tests.xml # API tests
├── .github/
│ └── workflows/
│ └── test-automation.yml # GitHub Actions workflow
├── aws-codepipeline/
│ ├── buildspec.yml # AWS CodeBuild spec
│ └── cloudformation-template.yml # AWS infrastructure
├── azure-pipelines.yml # Azure DevOps pipeline
├── Jenkinsfile # Jenkins pipeline
├── pom.xml # Maven configuration
├── .gitignore # Git ignore rules
└── README.md # This file
Before you begin, ensure you have the following installed:
Windows:
# Download from: https://adoptium.net/
# Or use Chocolatey:
choco install temurin11macOS:
# Using Homebrew:
brew install openjdk@11
# Add to PATH:
echo 'export PATH="/usr/local/opt/openjdk@11/bin:$PATH"' >> ~/.zshrc
source ~/.zshrcLinux (Ubuntu/Debian):
sudo apt update
sudo apt install openjdk-11-jdkVerify installation:
java -version
# Should show: openjdk version "11.x.x"Windows:
choco install mavenmacOS:
brew install mavenLinux:
sudo apt install mavenVerify installation:
mvn -version
# Should show: Apache Maven 3.x.xThe framework uses WebDriverManager to automatically download browser drivers. Just ensure you have a browser installed:
- Chrome: https://www.google.com/chrome/
- Firefox: https://www.mozilla.org/firefox/
- Edge: https://www.microsoft.com/edge
git clone https://github.com/amitbad/Java-Selenium-Automation-Framework.git
cd Java-Selenium-Automation-Frameworkmvn clean install -DskipTests# Copy the environment template
cp src/main/resources/config/env.properties.template src/main/resources/config/env.properties
# Edit with your values
nano src/main/resources/config/env.properties # or use any text editor# Run a quick test to verify everything works
mvn test -Dtest=SampleApiTest#testGetPosts| File | Purpose |
|---|---|
config.properties |
Default configuration (committed to repo) |
env.properties |
Environment-specific secrets (gitignored) |
| Environment Variables | Override any configuration at runtime |
- Environment Variables - Highest priority
- env.properties - Local overrides
- config.properties - Default values
# Browser Configuration
browser=chrome # chrome, firefox, edge, safari
headless=false # true for CI/CD
browser.maximize=true
browser.implicit.wait=10
browser.explicit.wait=30
# Application URLs
base.url=https://your-app.com
api.base.url=https://api.your-app.com
# Screenshot Configuration
screenshot.on.failure=true
screenshot.path=target/screenshots
# Retry Configuration
retry.count=2
# Browser Attachment Mode
attach.browser=false
debug.port=9222Set these environment variables for sensitive data:
# Linux/macOS
export BASE_URL="https://your-app.com"
export API_BASE_URL="https://api.your-app.com"
export TEST_USERNAME="your_username"
export TEST_PASSWORD="your_password"
# Windows (PowerShell)
$env:BASE_URL="https://your-app.com"
$env:API_BASE_URL="https://api.your-app.com"
$env:TEST_USERNAME="your_username"
$env:TEST_PASSWORD="your_password"# Run all tests
mvn clean test
# Run with specific profile
mvn clean test -Psmoke # Smoke tests only
mvn clean test -Pregression # Regression tests
mvn clean test -Papi # API tests only
mvn clean test -Pall # All tests (default)
# Run specific test class
mvn test -Dtest=LoginTest
# Run specific test method
mvn test -Dtest=LoginTest#testSuccessfulLogin
# Run tests with specific browser
mvn test -Dbrowser=firefox
# Run in headless mode
mvn test -Dheadless=true
# Run with multiple parameters
mvn clean test -Psmoke -Dbrowser=chrome -Dheadless=true# Run specific suite
mvn test -DsuiteXmlFile=src/test/resources/testng-suites/smoke-tests.xmlEdit the TestNG XML file to configure parallel execution:
<suite name="Parallel Suite" parallel="classes" thread-count="3">
<!-- tests -->
</suite>- Separation of Concerns - Locators are separate from code
- Easy Maintenance - Update locators without changing code
- Readability - Clear, structured format
- Reusability - Share locators across tests
{
"pageName": "LoginPage",
"description": "Locators for the Login Page",
"locators": {
"usernameInput": {
"type": "id",
"value": "username",
"description": "Username input field"
},
"loginButton": {
"type": "css",
"value": "button[type='submit']",
"description": "Login submit button"
},
"errorMessage": {
"type": "xpath",
"value": "//div[@class='error']",
"description": "Error message element"
}
}
}| Type | Description | Example |
|---|---|---|
id |
Element ID | "username" |
css |
CSS Selector | "button.submit" |
xpath |
XPath | "//input[@name='email']" |
name |
Name attribute | "email" |
className |
Class name | "btn-primary" |
linkText |
Link text | "Click Here" |
partialLinkText |
Partial link text | "Click" |
tagName |
HTML tag | "button" |
public class LoginPage extends BasePage {
public LoginPage() {
super("login-page.json"); // Load locators from JSON
}
public void enterUsername(String username) {
enterText("usernameInput", username); // Use locator name
}
public void clickLogin() {
click("loginButton");
}
}- Create JSON locator file in
src/main/resources/locators/:
// new-page.json
{
"pageName": "NewPage",
"locators": {
"headerTitle": {
"type": "css",
"value": "h1.title",
"description": "Page header title"
}
}
}- Create Page class:
package com.automation.pages;
import com.automation.base.BasePage;
import io.qameta.allure.Step;
public class NewPage extends BasePage {
public NewPage() {
super("new-page.json");
}
@Step("Get header title")
public String getHeaderTitle() {
return getText("headerTitle");
}
}| Method | Description |
|---|---|
click(elementName) |
Click on element |
enterText(elementName, text) |
Enter text in input |
getText(elementName) |
Get element text |
getAttribute(elementName, attr) |
Get attribute value |
isElementDisplayed(elementName) |
Check if visible |
isElementEnabled(elementName) |
Check if enabled |
selectByVisibleText(elementName, text) |
Select dropdown |
hoverOver(elementName) |
Mouse hover |
scrollToElement(elementName) |
Scroll to element |
waitForElement(elementName) |
Wait for visibility |
public class MyApiTest extends BaseApiTest {
@Test
public void testGetUser() {
Response response = apiClient.get("/users/1");
assertStatusCode(response, 200);
assertResponseContainsKey(response, "id");
assertResponseKeyEquals(response, "name", "John Doe");
}
@Test
public void testCreateUser() {
Map<String, Object> body = new HashMap<>();
body.put("name", "Jane Doe");
body.put("email", "jane@example.com");
Response response = apiClient.post("/users", body);
assertStatusCode(response, 201);
}
}| Method | Description |
|---|---|
get(endpoint) |
GET request |
get(endpoint, params) |
GET with query params |
post(endpoint, body) |
POST request |
put(endpoint, body) |
PUT request |
patch(endpoint, body) |
PATCH request |
delete(endpoint) |
DELETE request |
setAuthToken(token) |
Set Bearer token |
addHeader(name, value) |
Add custom header |
Generate and view Allure reports:
# Run tests
mvn clean test
# Generate report
mvn allure:report
# Serve report (opens in browser)
mvn allure:serveReport location: target/site/allure-maven-plugin/index.html
Extent reports are generated automatically after test execution.
Report location: target/reports/TestReport_[timestamp].html
Screenshots are automatically captured on test failure when screenshot.on.failure=true.
// In test or page object
takeScreenshot("custom_screenshot_name");target/screenshots/[testname]_[timestamp].png
Browser attachment allows you to reuse an existing browser session, which is useful for:
- Faster test development and debugging
- Maintaining login state across test runs
- Inspecting browser state after test failure
# macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome_debug
# Windows
"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir=C:\temp\chrome_debug
# Linux
google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome_debug# In config.properties or env.properties
attach.browser=true
debug.port=9222Tests will now attach to the existing browser instead of starting a new one.
mvn test -Dattach.browser=trueNote: The browser will remain open after tests complete for inspection.
Add email settings to env.properties:
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USERNAME=your_email@gmail.com
EMAIL_PASSWORD=your_app_password
EMAIL_FROM=your_email@gmail.com
EMAIL_TO=recipient@example.com- Enable 2-Factor Authentication on your Google account
- Generate an App Password:
- Go to Google Account → Security → App passwords
- Generate a new app password for "Mail"
- Use this password in
EMAIL_PASSWORD
// Send report after test execution
EmailUtils.sendTestCompletionEmail(
passedCount,
failedCount,
skippedCount,
"target/reports/TestReport.html"
);The workflow is configured to run manually only by default.
-
Add Secrets in GitHub Repository:
- Go to Repository → Settings → Secrets and variables → Actions
- Add the following secrets:
BASE_URL- Your application URLAPI_BASE_URL- Your API URLTEST_USERNAME- Test user usernameTEST_PASSWORD- Test user password
-
Run Workflow Manually:
- Go to Actions tab
- Select "Test Automation Pipeline"
- Click "Run workflow"
- Select options (test suite, browser, environment)
- Click "Run workflow"
-
Enable Automatic Runs (Optional):
- Edit
.github/workflows/test-automation.yml - Uncomment the
pushandpull_requesttriggers
- Edit
- Test results appear in the Actions tab
- Download artifacts (reports, screenshots) from the workflow run
- Jenkins with Pipeline plugin
- JDK 11 configured as "JDK11"
- Maven 3 configured as "Maven3"
- Allure plugin (optional, for reports)
-
Create Pipeline Job:
- New Item → Pipeline
- Name: "Test-Automation"
-
Configure Pipeline:
- Pipeline → Definition: "Pipeline script from SCM"
- SCM: Git
- Repository URL: Your repo URL
- Script Path:
Jenkinsfile
-
Add Credentials:
- Manage Jenkins → Credentials
- Add credentials with IDs:
base-urlapi-base-urltest-usernametest-password
-
Configure Tools:
- Manage Jenkins → Global Tool Configuration
- Add JDK installation named "JDK11"
- Add Maven installation named "Maven3"
-
Run Pipeline:
- Open the job
- Click "Build with Parameters"
- Select test suite, browser, environment
- Click "Build"
- Manage Jenkins → Plugins → Available
- Search "Allure"
- Install "Allure Jenkins Plugin"
- Configure in Global Tool Configuration
-
Create Pipeline:
- Pipelines → New Pipeline
- Select your repository
- Choose "Existing Azure Pipelines YAML file"
- Select
/azure-pipelines.yml
-
Add Variables:
- Edit Pipeline → Variables
- Add variables (mark as secret where needed):
BASE_URLAPI_BASE_URLTEST_USERNAMETEST_PASSWORD
-
Run Pipeline:
- Click "Run pipeline"
- Select parameters
- Click "Run"
- Test results in "Tests" tab
- Download artifacts from "Summary" tab
-
Create Secrets in AWS Secrets Manager:
aws secretsmanager create-secret \ --name test-automation/secrets \ --secret-string '{"BASE_URL":"https://your-app.com","API_BASE_URL":"https://api.your-app.com","TEST_USERNAME":"user","TEST_PASSWORD":"pass"}' -
Deploy CloudFormation Stack:
aws cloudformation create-stack \ --stack-name test-automation-pipeline \ --template-body file://aws-codepipeline/cloudformation-template.yml \ --parameters \ ParameterKey=GitHubOwner,ParameterValue=your-username \ ParameterKey=GitHubRepo,ParameterValue=your-repo \ ParameterKey=GitHubBranch,ParameterValue=main \ ParameterKey=GitHubToken,ParameterValue=your-github-token \ --capabilities CAPABILITY_NAMED_IAM -
Manual Trigger:
- Go to AWS CodePipeline console
- Select your pipeline
- Click "Release change"
# Create CodeBuild project manually and run:
aws codebuild start-build --project-name test-automation-build# Using Scoop
scoop install allure
# Or using Chocolatey
choco install allurebrew install allure# Download and extract
wget https://github.com/allure-framework/allure2/releases/download/2.24.0/allure-2.24.0.tgz
tar -xzf allure-2.24.0.tgz
sudo mv allure-2.24.0 /opt/allure
# Add to PATH
echo 'export PATH="/opt/allure/bin:$PATH"' >> ~/.bashrc
source ~/.bashrcallure --version# After running tests
allure generate target/allure-results --clean -o target/allure-report
# Open report in browser
allure open target/allure-report- Prefer
id>css>xpath - Use meaningful, stable locators
- Avoid dynamic IDs or classes
- Each test should be independent
- Don't rely on test execution order
- Clean up test data after tests
- Use explicit waits over implicit waits
- Avoid
Thread.sleep() - Use appropriate wait conditions
- Never commit sensitive data
- Use environment variables for secrets
- Keep configuration externalized
- Add meaningful test descriptions
- Use Allure annotations (
@Step,@Description) - Capture screenshots on failure
- Follow Page Object Model
- Keep tests focused and small
- Use meaningful method names
Solution: WebDriverManager handles this automatically.
Ensure you have internet connectivity on first run.
Solution:
- Check if locator is correct
- Add explicit wait before interaction
- Verify element is in viewport
Solution:
- Set window size: --window-size=1920,1080
- Check for elements that behave differently in headless
Solution:
mvn clean test
mvn allure:report
# Check target/allure-results has files
Solution:
- Verify SMTP settings
- For Gmail, use App Password
- Check firewall/network restrictions
Enable debug logging:
# In log4j2.xml, change level to DEBUG
<Logger name="com.automation" level="DEBUG">- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
For issues and questions:
- Create an issue in the GitHub repository
- Check existing issues for solutions
Happy Testing! 🚀