Complete Hybrid Selenium Framework - Ready to Use
This is the full, production-ready implementation of a Hybrid Selenium Framework using Page Object Model (POM) and TestNG. All classes, utilities, and configuration files are included with complete working code.
Project Structure Overview
src/ ├── main/ │ ├── java/ │ │ ├── config/ │ │ │ └── ConfigReader.java │ │ ├── pages/ │ │ │ └── LoginPage.java │ │ ├── utilities/ │ │ │ ├── DriverManager.java │ │ │ └── ExcelReader.java │ │ └── base/ │ │ └── BaseTest.java │ └── resources/ │ ├── config.properties │ └── testdata/ │ └── LoginData.xlsx ├── test/ │ ├── java/tests/ │ │ └── LoginTest.java │ └── resources/ │ └── testng.xml └── pom.xml
1. pom.xml - Complete Dependencies
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.automation</groupId>
<artifactId>selenium-pom-framework</artifactId>
<version>1.0</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.17.0</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.9.0</version>
</dependency>
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>5.1.1</version>
</dependency>
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. config.properties - Configuration File
File location: src/main/resources/config.properties
browser=chrome url=https://login.salesforce.com timeout=10 headless=false
3. ConfigReader.java - Read Configuration Properties
Location: src/main/java/config/ConfigReader.java
package config;
import java.io.FileInputStream;
import java.util.Properties;
public class ConfigReader {
private static Properties properties;
static {
try {
properties = new Properties();
properties.load(new FileInputStream("src/main/resources/config.properties"));
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getProperty(String key) {
return properties.getProperty(key);
}
}
4. DriverManager.java - WebDriver Factory
Location: src/main/java/utilities/DriverManager.java
package utilities;
import config.ConfigReader;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.firefox.FirefoxDriver;
public class DriverManager {
public static WebDriver getDriver() {
String browser = ConfigReader.getProperty("browser");
if ("chrome".equalsIgnoreCase(browser)) {
WebDriverManager.chromedriver().setup();
ChromeOptions options = new ChromeOptions();
if (Boolean.parseBoolean(ConfigReader.getProperty("headless"))) {
options.addArguments("--headless");
}
options.addArguments("--disable-notifications");
return new ChromeDriver(options);
} else {
WebDriverManager.firefoxdriver().setup();
return new FirefoxDriver();
}
}
}
5. ExcelReader.java - Data-Driven Test Support
Location: src/main/java/utilities/ExcelReader.java
package utilities;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileInputStream;
import java.io.IOException;
public class ExcelReader {
public static Object[][] getData(String filePath, String sheetName) {
try (FileInputStream fis = new FileInputStream(filePath);
Workbook workbook = new XSSFWorkbook(fis)) {
Sheet sheet = workbook.getSheet(sheetName);
int rows = sheet.getLastRowNum();
int cells = sheet.getRow(0).getLastCellNum();
Object[][] data = new Object[rows][cells];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cells; j++) {
data[i][j] = sheet.getRow(i + 1).getCell(j).getStringCellValue();
}
}
return data;
} catch (IOException e) {
throw new RuntimeException("Excel read error: " + e.getMessage());
}
}
}
6. LoginPage.java - Page Object Model
Location: src/main/java/pages/LoginPage.java
package pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
public class LoginPage {
private WebDriver driver;
private WebDriverWait wait;
@FindBy(xpath = "//input[contains(@id,'username')]")
private WebElement usernameField;
@FindBy(xpath = "//input[contains(@id,'password')]")
private WebElement passwordField;
@FindBy(xpath = "//input[@type='submit' or contains(@value,'Log')]")
private WebElement loginButton;
@FindBy(xpath = "//div[contains(@class,'error')]")
private WebElement errorMessage;
public LoginPage(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, 10);
PageFactory.initElements(driver, this);
}
public void enterUsername(String username) {
wait.until(ExpectedConditions.visibilityOf(usernameField));
usernameField.clear();
usernameField.sendKeys(username);
}
public void enterPassword(String password) {
passwordField.clear();
passwordField.sendKeys(password);
}
public void clickLogin() {
loginButton.click();
}
public String getErrorMessage() {
return errorMessage.getText();
}
public void login(String username, String password) {
enterUsername(username);
enterPassword(password);
clickLogin();
}
}
7. BaseTest.java - Test Base Class
Location: src/test/java/base/BaseTest.java
package base;
import config.ConfigReader;
import org.openqa.selenium.WebDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import pages.LoginPage;
import utilities.DriverManager;
public class BaseTest {
protected WebDriver driver;
protected LoginPage loginPage;
@BeforeMethod
public void setup() {
driver = DriverManager.getDriver();
driver.manage().window().maximize();
driver.get(ConfigReader.getProperty("url"));
loginPage = new LoginPage(driver);
}
@AfterMethod
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}
8. LoginTest.java - Test Class with Data Provider
Location: src/test/java/tests/LoginTest.java
package tests;
import base.BaseTest;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import utilities.ExcelReader;
public class LoginTest extends BaseTest {
@DataProvider(name = "loginData")
public Object[][] getLoginData() {
return ExcelReader.getData("src/main/resources/testdata/LoginData.xlsx", "Sheet1");
}
@Test(dataProvider = "loginData", groups = "smoke")
public void validLoginTest(String username, String password) {
loginPage.login(username, password);
Assert.assertTrue(driver.getTitle().contains("Salesforce"));
}
@Test(groups = "negative")
public void invalidLoginTest() {
loginPage.login("invalid@test.com", "wrongpass");
Assert.assertTrue(loginPage.getErrorMessage().contains("Error"));
}
}
9. testng.xml - Test Suite Configuration
Location: src/test/resources/testng.xml
<?xml version="1.0" encoding="UTF-8"?>
<suite name="SalesforceRegressionSuite" parallel="methods" thread-count="3">
<test name="SmokeTests">
<groups>
<run>
<include name="smoke"/>
</run>
</groups>
<classes>
<class name="tests.LoginTest"/>
</classes>
</test>
<test name="NegativeTests">
<groups>
<run>
<include name="negative"/>
</run>
</groups>
<classes>
<class name="tests.LoginTest"/>
</classes>
</test>
</suite>
0 Comments