Skip to main content
/tayyab/portfolio — zsh
tayyab
TA
// dispatch.read --classified=false --access-level: public

Selenium Java Framework Setup: Step-by-Step (2026)

March 2, 2026 EST. READ: 16 MIN #Test Automation

Selenium Java Framework Setup: Step-by-Step (2026)

Selenium with Java remains the most widely used test automation stack in enterprises. While Playwright is newer and faster, Selenium's maturity, extensive documentation, and legacy system support make it indispensable.

I've set up Selenium Java frameworks on 4 projects. This guide distills lessons learned into a copy-paste-ready setup.

Prerequisites

  • Java 11+ installed
  • Maven 3.6+
  • IDE: IntelliJ or Eclipse

Table of Contents

  1. Maven Project Setup
  2. Dependency Configuration
  3. WebDriver Management
  4. Page Object Model
  5. Test Configuration
  6. Parallel Execution
  7. Real Project Example
  8. Troubleshooting

Maven Project Setup

Create Project

mvn archetype:generate \n  -DgroupId=com.automation \n  -DartifactId=selenium-automation \n  -DarchetypeArtifactId=maven-archetype-quickstart \n  -DinteractiveMode=false

cd selenium-automation

Project Structure

selenium-automation/
├── src/
│   ├── main/
│   │   └── java/
│   │       ├── utils/
│   │       │   ├── DriverManager.java
│   │       │   └── WaitUtils.java
│   │       └── config/
│   │           └── ConfigReader.java
│   └── test/
│       ├── java/
│       │   ├── pages/
│       │   │   ├── BasePage.java
│       │   │   └── LoginPage.java
│       │   ├── tests/
│       │   │   └── LoginTest.java
│       │   └── TestBase.java
│       └── resources/
│           ├── config.properties
│           └── testng.xml
├── pom.xml
└── README.md

Dependency Configuration

pom.xml

<?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-automation</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <selenium.version>4.15.0</selenium.version>
    <testng.version>7.8.1</testng.version>
  </properties>

  <dependencies>
    <!-- Selenium WebDriver -->
    <dependency>
      <groupId>org.seleniumhq.selenium</groupId>
      <artifactId>selenium-java</artifactId>
      <version>${selenium.version}</version>
    </dependency>

    <!-- WebDriverManager (handles driver downloads) -->
    <dependency>
      <groupId>io.github.bonigarcia</groupId>
      <artifactId>webdrivermanager</artifactId>
      <version>5.6.2</version>
    </dependency>

    <!-- TestNG (test runner) -->
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>${testng.version}</version>
      <scope>test</scope>
    </dependency>

    <!-- Log4j (logging) -->
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <version>2.21.0</version>
    </dependency>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-api</artifactId>
      <version>2.21.0</version>
    </dependency>

    <!-- Assertions (AssertJ for fluent assertions) -->
    <dependency>
      <groupId>org.assertj</groupId>
      <artifactId>assertj-core</artifactId>
      <version>3.24.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <!-- Compiler Plugin -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.11.0</version>
        <configuration>
          <source>11</source>
          <target>11</target>
        </configuration>
      </plugin>

      <!-- Surefire (runs tests in Maven) -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>3.1.0</version>
        <configuration>
          <suiteXmlFiles>
            <suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
          </suiteXmlFiles>
          <parallel>methods</parallel>
          <threadCount>4</threadCount>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

WebDriver Management

DriverManager.java

public class DriverManager {
  private static final ThreadLocal<WebDriver> driver = new ThreadLocal<>();

  public static void initializeDriver(String browserName) {
    WebDriver webDriver;

    switch (browserName.toLowerCase()) {
      case "chrome":
        WebDriverManager.chromedriver().setup();
        webDriver = new ChromeDriver(getChromeOptions());
        break;
      case "firefox":
        WebDriverManager.firefoxdriver().setup();
        webDriver = new FirefoxDriver();
        break;
      case "edge":
        WebDriverManager.edgedriver().setup();
        webDriver = new EdgeDriver();
        break;
      default:
        throw new IllegalArgumentException("Invalid browser: " + browserName);
    }

    driver.set(webDriver);
  }

  public static WebDriver getDriver() {
    return driver.get();
  }

  public static void quitDriver() {
    WebDriver webDriver = driver.get();
    if (webDriver != null) {
      webDriver.quit();
      driver.remove();
    }
  }

  private static ChromeOptions getChromeOptions() {
    ChromeOptions options = new ChromeOptions();
    options.addArguments("--start-maximized");
    options.addArguments("--disable-blink-features=AutomationControlled");
    options.setExperimentalOption("excludeSwitches", new String[]{"enable-automation"});
    return options;
  }
}

Page Object Model

BasePage.java

public class BasePage {
  protected WebDriver driver;
  protected WebDriverWait wait;
  protected static final Logger logger = LogManager.getLogger();

  public BasePage() {
    this.driver = DriverManager.getDriver();
    this.wait = new WebDriverWait(driver, Duration.ofSeconds(5));
  }

  protected void click(By locator) {
    wait.until(ExpectedConditions.elementToBeClickable(locator)).click();
  }

  protected void type(By locator, String text) {
    WebElement element = wait.until(ExpectedConditions.presenceOfElementLocated(locator));
    element.clear();
    element.sendKeys(text);
  }

  protected String getText(By locator) {
    return wait.until(ExpectedConditions.presenceOfElementLocated(locator)).getText();
  }

  protected boolean isDisplayed(By locator) {
    try {
      return driver.findElement(locator).isDisplayed();
    } catch (NoSuchElementException e) {
      return false;
    }
  }
}

LoginPage.java

public class LoginPage extends BasePage {
  private static final Logger logger = LogManager.getLogger();

  // Locators
  private final By emailField = By.id("email");
  private final By passwordField = By.id("password");
  private final By submitButton = By.xpath("//button[@type='submit']");
  private final By errorMessage = By.className("error-message");

  public void login(String email, String password) {
    logger.info("Logging in with email: " + email);
    type(emailField, email);
    type(passwordField, password);
    click(submitButton);
    wait.until(ExpectedConditions.urlContains("/dashboard"));
  }

  public String getErrorMessage() {
    return getText(errorMessage);
  }

  public boolean isErrorMessageDisplayed() {
    return isDisplayed(errorMessage);
  }
}

Test Configuration

testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Automation Suite" parallel="methods" thread-count="4">
  <listeners>
    <listener class-name="listeners.TestListener"/>
  </listeners>

  <test name="Login Tests">
    <classes>
      <class name="tests.LoginTest"/>
    </classes>
  </test>

  <test name="Dashboard Tests">
    <classes>
      <class name="tests.DashboardTest"/>
    </classes>
  </test>
</suite>

TestBase.java

public class TestBase {
  @BeforeMethod
  public void setUp() {
    String browser = System.getProperty("browser", "chrome");
    DriverManager.initializeDriver(browser);
    DriverManager.getDriver().get("https://example.com");
  }

  @AfterMethod
  public void tearDown() {
    DriverManager.quitDriver();
  }
}

Parallel Execution

Run Tests in Parallel

# Run with 4 threads
mvn test -Dthread-count=4

# Run specific test class
mvn test -Dtest=LoginTest

# Run with specific browser
mvn test -Dbrowser=firefox

Real Project Example

On a fintech automation project:

Setup:

  • 120 E2E tests with Selenium Java
  • Page Objects: 15 pages
  • Parallel execution: 4 workers

Results:

  • Sequential: 45 minutes → Parallel: 12 minutes (3.7x faster)
  • Maintenance: 20 hours/month → 4 hours/month (Page Objects)

Troubleshooting

Issue: "ChromeDriver path not found"

  • Fix: WebDriverManager automatically downloads drivers. Ensure internet access.

Issue: "StaleElementReferenceException"

  • Fix: Re-find element after page change. Use explicit waits.

Issue: "ElementNotInteractableException"

  • Fix: Wait for element to be clickable:
wait.until(ExpectedConditions.elementToBeClickable(locator)).click();

FAQ

Q: Selenium or Playwright?
A: Selenium for legacy systems, large enterprises. Playwright for new projects.

Q: TestNG or JUnit?
A: TestNG. Better parallel execution, more flexible.

Q: How many tests per file?
A: 5-10 per file. Organize by feature.

Q: How to handle dynamic waits?
A: Use WebDriverWait with ExpectedConditions. Never use Thread.sleep().

Tayyab Akmal
// author

Tayyab Akmal

AI & QA Automation Engineer

I've caught critical bugs in fintech, e-commerce, and SaaS platforms — then built the automation that prevents them from shipping again. 6+ years scaling test automation and AI-driven QA.

// feedback_channel

FOUND THIS USEFUL?

Share your thoughts or let's discuss automation testing strategies.

→ Start Conversation
Available for hire