This is where everything comes together. We are building real test classes for the TesterRank Banking Portal (/banking). These tests use BaseTest for setup, page objects for interactions, DataProviders for test data, groups for categorization, and logging for debugging.
Before writing tests, we need the page objects. Here is the DashboardPage and TransferPage for the Banking Portal.
package com.testerrank.pages.banking;
import com.testerrank.base.BasePage;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class DashboardPage extends BasePage {
private final By welcomeMessage =
By.cssSelector("[data-testid='welcome-msg']");
private final By accountBalance =
By.cssSelector("[data-testid='account-balance']");
private final By transferLink =
By.cssSelector("[data-testid='transfer-link']");
private final By transactionHistory =
By.cssSelector("[data-testid='transaction-list']");
private final By logoutButton =
By.cssSelector("[data-testid='logout-btn']");
public DashboardPage(WebDriver driver) {
super(driver);
}
public boolean isLoaded() {
try {
waitForVisible(welcomeMessage);
return true;
} catch (Exception e) {
return false;
}
}
public String getWelcomeMessage() {
return getText(welcomeMessage);
}
public String getAccountBalance() {
return getText(accountBalance);
}
public TransferPage clickTransfer() {
logger.info("Navigating to Transfer page");
click(transferLink);
return new TransferPage(driver);
}
public int getTransactionCount() {
return getElementCount(
By.cssSelector(
"[data-testid='transaction-list'] tr"));
}
public LoginPage logout() {
logger.info("Logging out");
click(logoutButton);
return new LoginPage(driver);
}
}package com.testerrank.pages.banking;
import com.testerrank.base.BasePage;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class TransferPage extends BasePage {
private final By fromAccount =
By.id("from-account");
private final By toAccountField =
By.id("to-account");
private final By amountField =
By.id("amount");
private final By descriptionField =
By.id("description");
private final By transferButton =
By.id("transfer-btn");
private final By confirmationMessage =
By.cssSelector("[data-testid='transfer-confirmation']");
private final By errorMessage =
By.cssSelector(".error-message");
public TransferPage(WebDriver driver) {
super(driver);
}
public void performTransfer(String fromAcct,
String toAcct,
String amount,
String description) {
logger.info("Transferring " + amount
+ " from " + fromAcct + " to " + toAcct);
selectByVisibleText(fromAccount, fromAcct);
type(toAccountField, toAcct);
type(amountField, amount);
type(descriptionField, description);
click(transferButton);
}
public boolean isConfirmationDisplayed() {
try {
waitForVisible(confirmationMessage);
return true;
} catch (Exception e) {
return false;
}
}
public String getConfirmationMessage() {
return getText(confirmationMessage);
}
public boolean isErrorDisplayed() {
return isDisplayed(errorMessage);
}
public String getErrorText() {
return getText(errorMessage);
}
public DashboardPage goBackToDashboard() {
driver.navigate().back();
return new DashboardPage(driver);
}
}package com.testerrank.tests.banking;
import com.testerrank.base.BaseTest;
import com.testerrank.pages.banking.DashboardPage;
import com.testerrank.pages.banking.LoginPage;
import com.testerrank.utils.DataProviders;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class LoginTests extends BaseTest {
private LoginPage loginPage;
@BeforeMethod
public void navigateToLogin() {
navigateTo("/banking");
loginPage = new LoginPage(getDriver());
}
@Test(priority = 1,
groups = {"smoke", "regression"},
description = "Verify valid login redirects to dashboard")
public void testSuccessfulLogin() {
logger.info("Testing successful login");
DashboardPage dashboard = loginPage.loginAs(
"testuser", "password123");
Assert.assertTrue(dashboard.isLoaded(),
"Dashboard should load after valid login");
Assert.assertTrue(
dashboard.getWelcomeMessage().contains("testuser"),
"Welcome message should contain username");
}
@Test(priority = 2,
groups = {"regression"},
description = "Verify error for invalid credentials")
public void testInvalidCredentials() {
loginPage.loginAs("wronguser", "wrongpass");
Assert.assertTrue(loginPage.isErrorDisplayed(),
"Error message should appear");
Assert.assertFalse(
loginPage.getErrorText().isEmpty(),
"Error message should not be empty");
}
@Test(priority = 3,
groups = {"regression"},
dataProvider = "loginData",
dataProviderClass = DataProviders.class,
description = "Data-driven login with multiple credentials")
public void testLoginDataDriven(String username,
String password,
String expected) {
logger.info("DDT Login: user=" + username
+ ", expected=" + expected);
loginPage.loginAs(username, password);
if ("success".equals(expected)) {
DashboardPage dashboard =
new DashboardPage(getDriver());
Assert.assertTrue(dashboard.isLoaded(),
"Dashboard should load for: " + username);
} else {
Assert.assertTrue(loginPage.isErrorDisplayed(),
"Error expected for: " + username
+ "/" + password);
}
}
@Test(priority = 4,
groups = {"regression"},
description = "Verify empty username shows error")
public void testEmptyUsername() {
loginPage.enterPassword("password123");
loginPage.clickLogin();
Assert.assertTrue(loginPage.isErrorDisplayed(),
"Error should appear for empty username");
}
@Test(priority = 5,
groups = {"smoke", "regression"},
description = "Verify logout returns to login page")
public void testLogout() {
DashboardPage dashboard = loginPage.loginAs(
"testuser", "password123");
Assert.assertTrue(dashboard.isLoaded());
dashboard.logout();
Assert.assertTrue(
getDriver().getCurrentUrl().contains("/banking"),
"Should return to login page after logout");
}
}package com.testerrank.tests.banking;
import com.testerrank.base.BaseTest;
import com.testerrank.pages.banking.DashboardPage;
import com.testerrank.pages.banking.LoginPage;
import com.testerrank.pages.banking.TransferPage;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class BankingE2ETests extends BaseTest {
private LoginPage loginPage;
@BeforeMethod
public void navigateToLogin() {
navigateTo("/banking");
loginPage = new LoginPage(getDriver());
}
@Test(groups = {"smoke", "regression"},
description = "Full flow: Login > Balance > Transfer > Verify > Logout")
public void testCompleteBankingFlow() {
// Step 1: Login
logger.info("Step 1: Logging in");
DashboardPage dashboard = loginPage.loginAs(
"testuser", "password123");
Assert.assertTrue(dashboard.isLoaded(),
"Dashboard should load after login");
// Step 2: Check initial balance
logger.info("Step 2: Checking initial balance");
String initialBalance = dashboard.getAccountBalance();
Assert.assertNotNull(initialBalance,
"Balance should be displayed");
logger.info("Initial balance: " + initialBalance);
// Step 3: Perform fund transfer
logger.info("Step 3: Performing fund transfer");
TransferPage transfer = dashboard.clickTransfer();
transfer.performTransfer(
"Savings", "1234567890", "500", "Monthly rent");
// Step 4: Verify transfer confirmation
logger.info("Step 4: Verifying confirmation");
Assert.assertTrue(
transfer.isConfirmationDisplayed(),
"Confirmation should appear after transfer");
Assert.assertTrue(
transfer.getConfirmationMessage().contains("500"),
"Confirmation should mention amount");
// Step 5: Verify updated balance
logger.info("Step 5: Checking updated balance");
DashboardPage updated = transfer.goBackToDashboard();
String newBalance = updated.getAccountBalance();
logger.info("Updated balance: " + newBalance);
// Step 6: Logout
logger.info("Step 6: Logging out");
updated.logout();
Assert.assertTrue(
getDriver().getCurrentUrl().contains("/banking"),
"Should return to login page");
logger.info("Banking E2E flow completed");
}
@Test(groups = {"regression"},
description = "Verify transfer with invalid account number fails")
public void testTransferInvalidAccount() {
DashboardPage dashboard = loginPage.loginAs(
"testuser", "password123");
TransferPage transfer = dashboard.clickTransfer();
transfer.performTransfer(
"Savings", "0000000000", "100", "Invalid test");
Assert.assertTrue(transfer.isErrorDisplayed(),
"Error for invalid account number");
}
@Test(groups = {"regression"},
description = "Verify transfer with zero amount fails")
public void testTransferZeroAmount() {
DashboardPage dashboard = loginPage.loginAs(
"testuser", "password123");
TransferPage transfer = dashboard.clickTransfer();
transfer.performTransfer(
"Savings", "1234567890", "0", "Zero amount test");
Assert.assertTrue(transfer.isErrorDisplayed(),
"Error for zero amount");
}
@Test(groups = {"regression"},
description = "Verify transfer with negative amount fails")
public void testTransferNegativeAmount() {
DashboardPage dashboard = loginPage.loginAs(
"testuser", "password123");
TransferPage transfer = dashboard.clickTransfer();
transfer.performTransfer(
"Savings", "1234567890", "-500", "Negative test");
Assert.assertTrue(transfer.isErrorDisplayed(),
"Error for negative amount");
}
}Q: Walk me through a complete end-to-end test in your framework.
A: Let me take the banking fund transfer test. The test class extends BaseTest, which starts Chrome in @BeforeMethod and closes it in @AfterMethod. In the test method, I first navigate to /banking and create a LoginPage object. I call loginPage.loginAs() which types credentials and clicks login — internally using BasePage methods with explicit waits. The method returns a DashboardPage object. I verify the balance is displayed, then call dashboard.clickTransfer() which navigates to the transfer page and returns a TransferPage object. I fill in transfer details using transfer.performTransfer() and verify the confirmation message. Each page object encapsulates its locators and actions, and the test reads like a story of what the user does.
Notice how each test method starts with navigating to the login page in @BeforeMethod. This ensures every test starts from a clean state. No test depends on another test running first. This is critical for parallel execution.
Key Point: Banking portal tests combine POM, DDT, BaseTest, and logging into clean, readable test methods. Each test is independent and starts from a fresh state.