Java-Selenium

Java Selenium Project Structure

Here is the enhanced Java, TestNG, Selenium, Maven project structure that incorporates Page Object Model (POM) with PageFactory, along with a .github folder for CI/CD pipelines (e.g., nightly and per-push builds) and a .gitignore file.


Project Structure

MyAutomationProject/
├── .github/
│   └── workflows/
│       ├── nightly-build.yml          # Nightly build pipeline
│       ├── push-build.yml             # Build triggered on push
├── .gitignore                         # Files and folders to ignore in git
├── pom.xml                            # Maven configuration file
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── myproject/
│   │   │           ├── base/
│   │   │           │   ├── BaseTest.java           # Base class for tests
│   │   │           │   └── DriverFactory.java      # Manages WebDriver instances
│   │   │           ├── config/
│   │   │           │   └── ConfigReader.java       # Reads configuration files
│   │   │           ├── pages/
│   │   │           │   ├── LoginPage.java          # Login Page with PageFactory
│   │   │           │   └── DashboardPage.java      # Dashboard Page with PageFactory
│   │   │           └── utils/
│   │   │               ├── TestUtils.java          # Shared utility methods
│   │   │               └── WaitUtils.java          # Explicit wait utility
│   └── test/
│       ├── java/
│       │   └── com/
│       │       └── myproject/
│       │           ├── tests/
│       │           │   ├── LoginTest.java          # Test cases for Login
│       │           │   └── RegressionSuite.java    # Regression Test Suite
│       │           ├── listeners/
│       │           │   └── TestListener.java       # TestNG listener implementation
│       │           └── data/
│       │               └── TestDataProvider.java   # Data provider for tests
│       └── resources/
│           ├── testng.xml                          # TestNG suite configuration
│           └── config.properties                   # Configuration properties
└── target/                                         # Maven build output

Example Files


.gitignore

# Maven specific files
target/
*.iml

# IntelliJ IDEA project files
.idea/
*.ipr
*.iws
*.iml

# Eclipse project files
.classpath
.project
.settings/

# OS-specific files
.DS_Store

# Log files
*.log

# Build-related files
*.class

.github/workflows/nightly-build.yml

name: Nightly Build

on:
  schedule:
    - cron: '0 2 * * *' # Runs every day at 2 AM UTC

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout repository
      uses: actions/checkout@v3

    - name: Set up Java
      uses: actions/setup-java@v3
      with:
        java-version: 11
        distribution: 'adopt'

    - name: Install dependencies
      run: mvn install

    - name: Run tests
      run: mvn test

.github/workflows/push-build.yml

name: Build on Push

on:
  push:
    branches:
      - main
      - 'feature/**'

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout repository
      uses: actions/checkout@v3

    - name: Set up Java
      uses: actions/setup-java@v3
      with:
        java-version: 11
        distribution: 'adopt'

    - name: Install dependencies
      run: mvn install

    - name: Run tests
      run: mvn test

pom.xml

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.myproject</groupId>
    <artifactId>MyAutomationProject</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>4.14.0</version>
        </dependency>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>7.8.0</version>
        </dependency>
        <dependency>
            <groupId>io.github.bonigarcia</groupId>
            <artifactId>webdrivermanager</artifactId>
            <version>5.4.0</version>
        </dependency>
    </dependencies>
</project>

BaseTest.java

package com.myproject.base;
import org.openqa.selenium.WebDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;

public class BaseTest {
    protected WebDriver driver;

    @BeforeMethod
    public void setup() {
        driver = DriverFactory.getDriver();
        driver.manage().window().maximize();
    }

    @AfterMethod
    public void teardown() {
        if (driver != null) {
            driver.quit();
        }
    }
}

DriverFactory.java

package com.myproject.base;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import io.github.bonigarcia.wdm.WebDriverManager;

public class DriverFactory {
    public static WebDriver getDriver() {
        WebDriverManager.chromedriver().setup();
        return new ChromeDriver();
    }
}

ConfigReader.java

package com.myproject.config;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

public class ConfigReader {
    private static Properties properties;

    static {
        try (FileInputStream fis = new FileInputStream("src/test/resources/config.properties")) {
            properties = new Properties();
            properties.load(fis);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("Failed to load config.properties");
        }
    }

    public static String get(String key) {
        return properties.getProperty(key);
    }
}

LoginPage.java

package com.myproject.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;

public class LoginPage {
    private WebDriver driver;

    @FindBy(id = "username")
    private WebElement usernameField;

    @FindBy(id = "password")
    private WebElement passwordField;

    @FindBy(id = "login")
    private WebElement loginButton;

    public LoginPage(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(driver, this);
    }

    public void login(String username, String password) {
        usernameField.sendKeys(username);
        passwordField.sendKeys(password);
        loginButton.click();
    }
}

WaitUtils.java

package com.myproject.utils;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;

public class WaitUtils {
    public static void waitForElement(WebDriver driver, WebElement element, int timeout) {
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(timeout));
        wait.until(ExpectedConditions.visibilityOf(element));
    }
}

LoginTest.java

package com.myproject.tests;
import com.myproject.base.BaseTest;
import com.myproject.pages.LoginPage;
import org.testng.Assert;
import org.testng.annotations.Test;

public class LoginTest extends BaseTest {

    @Test
    public void testLogin() {
        driver.get("https://example.com/login");
        LoginPage loginPage = new LoginPage(driver);
        loginPage.login("testuser", "password");
        Assert.assertEquals(driver.getTitle(), "Dashboard");
    }
}

TestListener.java

package com.myproject.listeners;
import org.testng.ITestListener;
import org.testng.ITestResult;

public class TestListener implements ITestListener {

    @Override
    public void onTestSuccess(ITestResult result) {
        System.out.println("Test Passed: " + result.getName());
    }

    @Override
    public void onTestFailure(ITestResult result) {
        System.out.println("Test Failed: " + result.getName());
    }
}

TestDataProvider.java

package com.myproject.data;
import org.testng.annotations.DataProvider;
public class TestDataProvider {

    @DataProvider(name = "loginData")
    public Object[][] loginData() {
        return new Object[][] {
            {"user1", "password1"},
            {"user2", "password2"}
        };
    }
}

testng.xml

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="MyAutomationSuite">
    <listeners>
        <listener class-name="com.myproject.listeners.TestListener" />
    </listeners>
    <test name="LoginTests">
        <classes>
            <class name="com.myproject.tests.LoginTest" />
        </classes>
    </test>
</suite>

config.properties

baseUrl=https://example.com
username=defaultUser
password=defaultPassword

This structure leverages PageFactory for managing web elements, ensuring cleaner and more maintainable code.

Java Selenium Extended Project Structure

Here’s the extended project structure, including the requested files: README.md, .github/CODEOWNERS, and .github/pull_request_template.md.


Updated Project Structure

MyAutomationProject/
├── .github/
│   └── workflows/
│       ├── nightly-build.yml          # Nightly build pipeline
│       ├── push-build.yml             # Build triggered on push
│   ├── CODEOWNERS                     # Code owners file
│   ├── pull_request_template.md       # Pull request template
├── .gitignore                         # Files and folders to ignore in git
├── README.md                          # Project documentation
├── pom.xml                            # Maven configuration file
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── myproject/
│   │   │           ├── base/
│   │   │           │   ├── BaseTest.java           # Base class for tests
│   │   │           │   └── DriverFactory.java      # Manages WebDriver instances
│   │   │           ├── config/
│   │   │           │   └── ConfigReader.java       # Reads configuration files
│   │   │           ├── pages/
│   │   │           │   ├── LoginPage.java          # Login Page with PageFactory
│   │   │           │   └── DashboardPage.java      # Dashboard Page with PageFactory
│   │   │           └── utils/
│   │   │               ├── TestUtils.java          # Shared utility methods
│   │   │               └── WaitUtils.java          # Explicit wait utility
│   └── test/
│       ├── java/
│       │   └── com/
│       │       └── myproject/
│       │           ├── tests/
│       │           │   ├── LoginTest.java          # Test cases for Login
│       │           │   └── RegressionSuite.java    # Regression Test Suite
│       │           ├── listeners/
│       │           │   └── TestListener.java       # TestNG listener implementation
│       │           └── data/
│       │               └── TestDataProvider.java   # Data provider for tests
│       └── resources/
│           ├── testng.xml                          # TestNG suite configuration
│           └── config.properties                   # Configuration properties
└── target/                                         # Maven build output

Examples of Added Files


README.md

# MyAutomationProject

## Overview
This project is a Selenium-based automation framework built with Java, TestNG, and Maven. It follows the Page Object Model (POM) with PageFactory for a clean and maintainable design.

## Features
- Automated browser testing with Selenium.
- Page Object Model with PageFactory.
- Test execution and reporting using TestNG.
- Continuous Integration using GitHub Actions (nightly builds and push-triggered builds).

## Project Structure

MyAutomationProject/ ├── .github/ ├── src/ ├── pom.xml ├── README.md ├── .gitignore


## Prerequisites
- Java 11 or higher.
- Maven installed.
- WebDriver binaries managed using WebDriverManager.

## How to Run Tests
1. Clone the repository.
2. Navigate to the project root.
3. Execute:
   ```bash
   mvn test

Continuous Integration

  • Nightly builds configured in .github/workflows/nightly-build.yml.
  • Builds triggered on each push to the main branch in .github/workflows/push-build.yml.

Contributing

  1. Fork the repository.
  2. Create a new branch for your feature.
  3. Commit your changes.
  4. Submit a pull request (PR).
---
#### **`.github/CODEOWNERS`**
```plaintext
# Code owners file
# Specify individuals or teams responsible for specific files or directories.
# Format: path @github-username

# Owners for all files
* @owner1 @owner2

# Owners for specific folders
.github/ @ci-team
src/main/ @dev-team
src/test/ @qa-team

.github/pull_request_template.md

# Pull Request Template

## Description
- Please include a summary of the changes and the related issue this PR addresses.

## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update

## Checklist
- [ ] Code follows the coding standards and guidelines.
- [ ] Tests have been added and pass locally.
- [ ] Documentation has been updated (if applicable).

## Related Issues
- Resolves #[issue-number]

## Screenshots (if applicable)
Include screenshots for UI-related changes.

## Additional Notes
Provide any additional context or details here.

How These Files Work

  1. README.md:

    • Provides an overview of the project, instructions for running tests, and contribution guidelines.
  2. .github/CODEOWNERS:

    • Defines ownership for code reviews. Specific users or teams are automatically assigned as reviewers for changes to designated files or directories.
  3. .github/pull_request_template.md:

    • A standardized template that contributors fill out when submitting pull requests.

Summary of Enhancements

  • CI/CD Pipelines:
    • Nightly and push-triggered builds in .github/workflows/.
  • Code Ownership:
    • Ensures clear responsibilities using .github/CODEOWNERS.
  • Pull Request Template:
    • Simplifies and standardizes the PR process.

This setup fosters better collaboration and ensures a well-documented, maintainable project.