Hybrid framework architecture in Selenium Java - Build an Automation Script
package tests; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import pages.LoginPage; import pages.DashboardPage; import java.time.Duration; public class LoginTest { private WebDriver driver; private WebDriverWait wait; private LoginPage loginPage; private DashboardPage dashboardPage; @BeforeClass public void setUp() { // Set path to chromedriver executable if needed driver = new ChromeDriver(); wait = new WebDriverWait(driver, Duration.ofSeconds(10)); driver.manage().window().maximize(); loginPage = new LoginPage(driver, wait); dashboardPage = new DashboardPage(driver, wait); } @Test public void testValidLogin() { driver.get("https://example.com/login"); loginPage.enterUsername("testuser"); loginPage.enterPassword("Test@1234"); loginPage.clickLoginButton(); // Wait for dashboard page URL wait.until(ExpectedConditions.urlContains("/dashboard")); String currentUrl = driver.getCurrentUrl(); Assert.assertTrue(currentUrl.contains("/dashboard"), "URL does not contain /dashboard"); String welcomeText = dashboardPage.getWelcomeMessage(); Assert.assertEquals(welcomeText, "Welcome, testuser!", "Welcome message mismatch"); } @AfterClass public void tearDown() { if (driver != null) { driver.quit(); } } } // File: pages/LoginPage.java package pages; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.support.ui.WebDriverWait; import org.openqa.selenium.support.ui.ExpectedConditions; public class LoginPage { private WebDriver driver; private WebDriverWait wait; private By usernameField = By.id("username"); private By passwordField = By.id("password"); private By loginButton = By.id("loginBtn"); public LoginPage(WebDriver driver, WebDriverWait wait) { this.driver = driver; this.wait = wait; } public void enterUsername(String username) { wait.until(ExpectedConditions.visibilityOfElementLocated(usernameField)).clear(); driver.findElement(usernameField).sendKeys(username); } public void enterPassword(String password) { wait.until(ExpectedConditions.visibilityOfElementLocated(passwordField)).clear(); driver.findElement(passwordField).sendKeys(password); } public void clickLoginButton() { wait.until(ExpectedConditions.elementToBeClickable(loginButton)).click(); } } // File: pages/DashboardPage.java package pages; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.support.ui.WebDriverWait; import org.openqa.selenium.support.ui.ExpectedConditions; public class DashboardPage { private WebDriver driver; private WebDriverWait wait; private By welcomeMessage = By.id("welcomeMsg"); public DashboardPage(WebDriver driver, WebDriverWait wait) { this.driver = driver; this.wait = wait; } public String getWelcomeMessage() { return wait.until(ExpectedConditions.visibilityOfElementLocated(welcomeMessage)).getText(); } }
This test uses Selenium WebDriver with TestNG in a hybrid framework style.
Setup: The @BeforeClass method initializes the ChromeDriver, WebDriverWait, and page objects.
Page Objects: LoginPage and DashboardPage classes encapsulate element locators and actions, following the Page Object Model pattern.
Test: The test navigates to the login page, enters username and password, clicks login, waits for the dashboard URL, and asserts the URL and welcome message.
Teardown: The @AfterClass method closes the browser.
Explicit waits ensure elements are ready before interaction, improving reliability. Separating page logic from test logic makes maintenance easier.
Now add data-driven testing with 3 different sets of login credentials (valid and invalid) using TestNG data provider.