Page Object Model(POM) Automation Testing Framework

Page Object Model(POM) Automation Testing Framework  

This blog post will guide you through setting up a robust Automation testing framework for Salesforce using Selenium, TestNG, and ExtentReports. This framework incorporates best practices for maintainability, reusability, and reporting.

1. Project Directory Structure

Before diving into the code, let's establish the project's directory structure:

SalesforceTesting/

├── src/

   ├── main/

      └── java/

          └── com/salesforce/

              ├── base/

                 ├── BaseTest.java

                 └── DriverManager.java

              ├── common/

                 └── Utility.java

              ├── listeners/

                 └── TestListener.java

              ├── pages/

                 └── LoginPage.java

              ├── reporting/

                 └── ExtentReportManager.java

              └── repository/

                  └── LocatorsRepository.java

   └── test/

       └── java/

           └── com/salesforce/

               └── tests/

                   └── LoginTest.java

├── pom.xml

├── testng.xml

└── run.bat

2. Core Dependencies (pom.xml)

First, let's define the necessary dependencies in your pom.xml file:

<project xmlns="http://maven.apache.org/POM/4.0.0"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.automationCodes</groupId>

    <artifactId>pageobject</artifactId>

    <version>1.0-SNAPSHOT</version>

 

    <properties>

        <selenium.version>4.16.1</selenium.version>

        <testng.version>7.8.0</testng.version>

        <webdrivermanager.version>5.6.3</webdrivermanager.version>

        <extentreports.version>5.1.1</extentreports.version>

        <commons.io.version>2.13.0</commons.io.version>

    </properties>

 

    <dependencies>

        <!-- Selenium -->

        <dependency>

            <groupId>org.seleniumhq.selenium</groupId>

            <artifactId>selenium-java</artifactId>

            <version>${selenium.version}</version>

        </dependency>

       

        <!-- TestNG -->

        <dependency>

            <groupId>org.testng</groupId>

            <artifactId>testng</artifactId>

            <version>${testng.version}</version>

        </dependency>

 

        <!-- WebDriverManager -->

        <dependency>

            <groupId>io.github.bonigarcia</groupId>

            <artifactId>webdrivermanager</artifactId>

            <version>${webdrivermanager.version}</version>

        </dependency>

 

        <!-- Extent Reports -->

        <dependency>

            <groupId>com.aventstack</groupId>

            <artifactId>extentreports</artifactId>

            <version>${extentreports.version}</version>

        </dependency>

 

        <!-- Apache Commons IO -->

        <dependency>

            <groupId>commons-io</groupId>

            <artifactId>commons-io</artifactId>

            <version>${commons.io.version}</version>

        </dependency>

    </dependencies>

 

    <build>

        <plugins>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-surefire-plugin</artifactId>

                <version>3.1.2</version>

                <configuration>

                    <suiteXmlFiles>

                        <suiteXmlFile>testng.xml</suiteXmlFile>

                    </suiteXmlFiles>

                </configuration>

            </plugin>

        </plugins>

    </build>

</project>

Explanation:

Ø  Selenium: For browser automation.

Ø  TestNG: Testing framework for structuring and running tests.

Ø  WebDriverManager: Simplifies WebDriver setup (no more manual driver downloads!).

Ø  ExtentReports: For generating detailed and visually appealing test reports.

Ø  Apache Commons IO: Useful utility for file operations.

3. Base Components

3.1. BaseTest.java

This abstract class handles the setup and teardown of your test environment.

package com.salesforce.base;

 

import org.openqa.selenium.WebDriver;

import org.testng.annotations.AfterSuite;

import org.testng.annotations.BeforeSuite;

import org.testng.annotations.Listeners;

 

@Listeners(com.salesforce.listeners.TestListener.class)

public abstract class BaseTest {

   

    protected WebDriver driver;

 

    @BeforeSuite

    public void setUpSuite() {

        // Initialize ExtentReports

        com.salesforce.reporting.ExtentReportManager.getInstance();

    }

 

    @BeforeSuite

    public void launchSalesforce() {

        driver = DriverManager.getDriver();

        String salesforceUrl = "https://login.salesforce.com"; // Salesforce login URL

        driver.get(salesforceUrl);

        System.out.println("Launched Salesforce URL: " + salesforceUrl);

    }

 

    @AfterSuite

    public void tearDownSuite() {

        // Quit the driver and flush ExtentReports

        DriverManager.quitDriver();

        com.salesforce.reporting.ExtentReportManager.getInstance().flush();

    }

}

Explanation:

Ø  @Listeners(com.salesforce.listeners.TestListener.class): This tells TestNG to use our custom TestListener class to handle test events (start, success, failure, etc.).

Ø  setUpSuite(): Initializes ExtentReports before the test suite begins.

Ø  launchSalesforce(): Launches the Salesforce login page using the DriverManager.

Ø  tearDownSuite(): Quits the WebDriver and flushes ExtentReports after the test suite completes.

3.2. DriverManager.java

This class manages the WebDriver instance. It ensures that only one WebDriver instance exists per test run and provides a centralized way to access and quit the driver.

package com.salesforce.base;

 

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.chrome.ChromeDriver;

import org.openqa.selenium.edge.EdgeDriver;

import org.openqa.selenium.firefox.FirefoxDriver;

import io.github.bonigarcia.wdm.WebDriverManager;

 

public class DriverManager {

    private static WebDriver driver;

   

    private DriverManager() {}

   

    public static WebDriver getDriver() {

        if(driver == null) {

            String browser = System.getProperty("browser", "chrome");

            switch(browser.toLowerCase()) {

                case "chrome":

                    WebDriverManager.chromedriver().setup();

                    driver = new ChromeDriver();

                    break;

                case "firefox":

                    WebDriverManager.firefoxdriver().setup();

                    driver = new FirefoxDriver();

                    break;

                case "edge":

                    WebDriverManager.edgedriver().setup();

                    driver = new EdgeDriver();

                    break;

                default:

                    throw new IllegalStateException("Invalid browser: " + browser);

            }

            driver.manage().window().maximize();

        }

        return driver;

    }

   

    public static void quitDriver() {

        if(driver != null) {

            driver.quit();

            driver = null;

        }

    }

}

 

 

Explanation:

Ø  getDriver(): This method implements the Singleton pattern. It checks if a WebDriver instance already exists. If not, it creates one based on the browser specified in the browser system property (defaults to Chrome). It uses WebDriverManager to automatically download and set up the appropriate driver.

Ø  quitDriver(): This method closes the WebDriver instance and sets the driver variable to null.

 

Utility Class

4.1 Utility.java

This class provides reusable utility methods for common Selenium actions.

Code Implementation

package com.salesforce.common;

 

import org.openqa.selenium.*;

import org.openqa.selenium.interactions.Actions;

import org.openqa.selenium.support.ui.ExpectedConditions;

import org.openqa.selenium.support.ui.WebDriverWait;

 

import com.salesforce.base.DriverManager;

 

import java.time.Duration;

import java.util.List;

import java.util.stream.Collectors;

 

public class Utility {

    private static final int TIMEOUT = 10;

   

    public static WebElement waitForElement(By locator) {

        return new WebDriverWait(DriverManager.getDriver(), Duration.ofSeconds(TIMEOUT))

            .until(ExpectedConditions.presenceOfElementLocated(locator));

    }

   

    public static void openPage(String url) {

        DriverManager.getDriver().get(url);

    }

   

    public static void click(By locator) {

        waitForElement(locator).click();

    }

   

    public static void sendKeys(By locator, String text) {

        WebElement element = waitForElement(locator);

        element.clear();

        element.sendKeys(text);

    }

   

    public static void doubleClick(By locator) {

        new Actions(DriverManager.getDriver())

            .doubleClick(waitForElement(locator))

            .perform();

    }

   

    public static void switchToWindow(int index) {

        List<String> windows = DriverManager.getDriver().getWindowHandles().stream().collect(Collectors.toList());

        DriverManager.getDriver().switchTo().window(windows.get(index));

    }

   

    public static boolean isElementPresent(By locator) {

        try {

            waitForElement(locator);

            return true;

        } catch(TimeoutException e) {

            return false;

        }

    }

}

Explanation

Ø  waitForElement(By locator): Waits for an element to be present on the page before interacting with it. This helps prevent flaky tests caused by timing issues.

Ø  click(By locator): Clicks on an element.

Ø  sendKeys(By locator, String text): Enters text into an element. It first clears the field to ensure no previous text remains.

Ø  doubleClick(By locator): Double clicks on an element.

Ø  switchToWindow(int index): Switches to a specific window based on its index.

Ø  isElementPresent(By locator): Checks if an element is present on the page.


Test Listener

5.1 TestListener.java

This class implements the ITestListener interface and is used to capture test execution events and log them to the ExtentReports.

Code Implementation

package com.salesforce.listeners;

 

import com.aventstack.extentreports.ExtentTest;

import com.aventstack.extentreports.Status;

import com.salesforce.base.DriverManager;

import com.salesforce.reporting.ExtentReportManager;

import org.testng.ITestContext;

import org.testng.ITestListener;

import org.testng.ITestResult;

 

public class TestListener implements ITestListener {

 

    private static ThreadLocal<ExtentTest> extentTest = new ThreadLocal<>();

 

    @Override

    public void onTestStart(ITestResult result) {

        ExtentTest test = ExtentReportManager.getInstance()

            .createTest(result.getMethod().getMethodName());

        extentTest.set(test);

    }

 

    @Override

    public void onTestSuccess(ITestResult result) {

        extentTest.get().log(Status.PASS, "Test Passed");

    }

 

    @Override

    public void onTestFailure(ITestResult result) {

        extentTest.get().log(Status.FAIL, "Test Failed");

        extentTest.get().fail(result.getThrowable());

    }

 

    @Override

    public void onTestSkipped(ITestResult result) {

        extentTest.get().log(Status.SKIP, "Test Skipped");

    }

 

    @Override

    public void onFinish(ITestContext context) {

        ExtentReportManager.getInstance().flush();

        DriverManager.quitDriver();

    }

}

Explanation

Ø  onTestStart(ITestResult result): This method is called when a test starts. It creates a new ExtentTest instance and associates it with the current thread.

Ø  onTestSuccess(ITestResult result): Logs a "Pass" status to the Extent report when a test passes.

Ø  onTestFailure(ITestResult result): Logs a "Fail" status and the exception to the Extent report when a test fails.

Ø  onTestSkipped(ITestResult result): Logs a "Skip" status to the Extent report when a test is skipped.

Ø  onFinish(ITestContext context): Flushes the Extent report and quits the WebDriver after all tests in the suite have finished.


Page Object Model (POM)

6.1 LoginPage.java

This class represents the Salesforce login page. It encapsulates the locators and actions related to the login page.

Code Implementation

package com.salesforce.pages;

 

import com.salesforce.common.Utility;

import com.salesforce.repository.LocatorsRepository;

 

public class LoginPage {

   

    public void enterUsername(String username) {

        Utility.sendKeys(LocatorsRepository.LoginPage.USERNAME, username);

    }

   

    public void enterPassword(String password) {

        Utility.sendKeys(LocatorsRepository.LoginPage.PASSWORD, password);

    }

   

    public void clickLogin() {

        Utility.click(LocatorsRepository.LoginPage.LOGIN_BUTTON);

    }

   

    public boolean isErrorMessageDisplayed() {

        return Utility.isElementPresent(LocatorsRepository.LoginPage.ERROR_MESSAGE);

    }

   

    public void loginWithCredentials(String username, String password) {

        enterUsername(username);

        enterPassword(password);

        clickLogin();

    }

}

Explanation

Ø  Each method in this class represents an action that can be performed on the login page (e.g., enterUsername, enterPassword, clickLogin).

Ø  The locators for the elements on the login page are stored in the LocatorsRepository class.


6.2. LocatorsRepository.java

This class stores all the locators for the elements in the application.

package com.salesforce.repository;

 

import org.openqa.selenium.By;

 

public class LocatorsRepository {

   

    public static class LoginPage {

        public static final By USERNAME = By.xpath("//input[@id='username']");

        public static final By PASSWORD = By.xpath("//input[@id='password']");

        public static final By LOGIN_BUTTON = By.xpath("//input[@id='Login']");

        public static final By ERROR_MESSAGE = By.xpath("//div[@id='error']");

        public static final By REMEMBER_ME = By.xpath("//input[@id='rememberUn']");

    }

}

Explanation:

Ø  This class uses nested static classes to group locators by page. This makes it easier to find and maintain locators.

Ø  All locators are defined as public static final By variables. This ensures that they are constants and can be accessed from anywhere in the project.


7. Reporting

7.1. ExtentReportManager.java

This class manages the ExtentReports instance.

package com.salesforce.reporting;

 

import com.aventstack.extentreports.ExtentReports;

import com.aventstack.extentreports.reporter.ExtentSparkReporter;

import java.text.SimpleDateFormat;

import java.util.Date;

 

public class ExtentReportManager {

   

    private static ExtentReports extent;

   

    public static ExtentReports getInstance() {

        if (extent == null) {

            String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());

            String reportName = "Salesforce-Test-Report-" + timestamp + ".html";

            ExtentSparkReporter reporter = new ExtentSparkReporter("reports/" + reportName);

            extent = new ExtentReports();

            extent.attachReporter(reporter);

            extent.setSystemInfo("Created By", "AutomationCodes by Ankit Vijay");

            extent.setSystemInfo("env", "qa");

            extent.setSystemInfo("Browser", System.getProperty("browser", "chrome"));

        }

        return extent;

    }

}

Explanation:

Ø  getInstance(): This method implements the Singleton pattern to ensure that only one ExtentReports instance exists.

Ø  It creates a new ExtentSparkReporter instance and attaches it to the ExtentReports instance. The report is saved to the reports directory with a timestamped filename.

Ø  It sets system information such as the environment and browser.


8. Test Cases

8.1. LoginTest.java

This class contains the test cases for the login page.

package com.salesforce.tests;

 

import com.salesforce.base.BaseTest;

import com.salesforce.pages.LoginPage;

import static org.testng.Assert.assertTrue;

import org.testng.annotations.Test;

 

public class LoginTest extends BaseTest {

 

    @Test

    public void testInvalidLogin() {

        LoginPage loginPage = new LoginPage();

        loginPage.loginWithCredentials("invalid@user.com", "wrongpass");

        assertTrue(loginPage.isErrorMessageDisplayed());

    }

 

    @Test

    public void testValidLogin() {

        LoginPage loginPage = new LoginPage();

        loginPage.loginWithCredentials("valid@user.com", "correctpass");

        // Add validation for successful login

    }

}

Explanation:

Ø  testInvalidLogin(): This test case attempts to log in with invalid credentials and verifies that the error message is displayed.

Ø  testValidLogin(): This test case attempts to log in with valid credentials. You would need to add validation to confirm a successful login (e.g., check for the presence of an element on the home page).


9. TestNG Configuration (testng.xml)

This file configures the TestNG test suite.

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">

<suite name="Salesforce Test Suite" verbose="1">

 

    <!-- 1. Define parameters -->

    <parameter name="browser" value="chrome" />

    <parameter name="env" value="A" />

 

    <!-- 2. Define listeners -->

    <listeners>

        <listener class-name="com.salesforce.listeners.TestListener" />

    </listeners>

 

    <!-- 3. Define parallel execution -->

    <test name="Parallel Tests">

        <classes>

            <class name="com.salesforce.tests.LoginTest" />

        </classes>

    </test>

 

</suite>

Explanation:

Ø  <suite>: Defines the test suite.

Ø  <parameter>: Defines parameters that can be used in the tests (e.g., browser, environment).

Ø  <listeners>: Specifies the listeners to use for the test suite.

Ø  <test>: Defines a test.

Ø  <classes>: Specifies the classes to include in the test.


10. Execution Script (run.bat)

This batch script simplifies the execution of the tests.

@echo off

REM Navigate to the project directory (if needed)

REM cd C:\Users\anvij\eclipse-workspace_Test\pageobject

 

REM Run Maven command to execute tests

mvn clean test

 

REM Pause to see the output

Pause

Explanation:

Ø  mvn clean test: This command tells Maven to clean the project (remove previously built files) and then run the tests.

Ø  pause: This command pauses the script after the tests have finished, so you can see the output.



Post a Comment

0 Comments