What is Selenium?
Selenium is an open-source tool for automating web applications across different browsers. It supports multiple programming languages like Java, Python, C#, Ruby, and JavaScript, making it a popular choice for testers worldwide.
Why Selenium?
- Free and open-source
- Supports multiple browsers (Chrome, Firefox, Edge, Safari)
- Supports multiple programming languages
- Large community and library support
- Can be integrated with tools like Maven, Jenkins, TestNG
How to Install Selenium
- Install Java JDK if not installed
- Install Eclipse IDE or IntelliJ IDEA for Java development
- Download Selenium WebDriver Java bindings from selenium.dev
- Add Selenium JAR files to your project’s build path
- Install ChromeDriver for your browser from ChromeDriver site
Creating Your First Selenium Script
Here’s a simple Java Selenium script that will open Google and search for “Selenium”:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class FirstSeleniumScript {
public static void main(String[] args) {
System.setProperty("webdriver.chrome.driver", "path/to/chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.get("https://www.google.com");
driver.findElement(By.name("q")).sendKeys("Selenium");
driver.findElement(By.name("q")).submit();
System.out.println("Page Title is: " + driver.getTitle());
driver.quit();
}
}
Best Practices
- Always close the browser using
driver.quit()
- Use explicit waits instead of hard-coded sleep
- Keep reusable methods in a utility class
- Use Page Object Model for better structure
Sample Website for Practice
You can practice Selenium on this sample site: OrangeHRM Demo
What are Locators?
Locators help Selenium identify elements on a web page to perform actions like click, type, or verify. They are critical for any Selenium automation script.
Types of Locators in Selenium
- By ID - Locates element by its unique ID attribute
- By Name - Uses the name attribute of elements
- By Class Name - Matches the class attribute
- By Tag Name - Locates elements by HTML tag (e.g., input, button)
- By Link Text - Finds links by the visible link text
- By Partial Link Text - Finds links by partial match of text
- By CSS Selector - Uses CSS syntax to find elements
- By XPath - Uses XPath queries to identify elements
Code Examples
// By ID
driver.findElement(By.id("username")).sendKeys("admin");
// By Name
driver.findElement(By.name("password")).sendKeys("admin123");
// By Class Name
driver.findElement(By.className("submit-btn")).click();
// By Tag Name
List<WebElement> inputs = driver.findElements(By.tagName("input"));
// By Link Text
driver.findElement(By.linkText("Forgot Password?")).click();
// By Partial Link Text
driver.findElement(By.partialLinkText("Forgot")).click();
// By CSS Selector
driver.findElement(By.cssSelector("input[type='text']")).sendKeys("sample");
// By XPath
driver.findElement(By.xpath("//button[@type='submit']")).click();
Best Practices
- Always prefer ID if available (most stable)
- Use CSS selectors or XPath for dynamic elements
- Use meaningful, short, readable locators
- Avoid absolute XPaths (like /html/body/div/div/div...)
Sample Project
Try identifying these elements on the sample demo website: OrangeHRM Demo.
- Username field →
id="txtUsername"
- Password field →
id="txtPassword"
- Login button →
id="btnLogin"
Use these locators in your practice scripts to automate login functionality.
What is XPath?
XPath stands for XML Path Language. It is a powerful way to navigate through HTML or XML elements to locate them precisely. Selenium uses XPath to find dynamic elements on web pages.
Types of XPath
- Absolute XPath - starts from the root (html tag) and goes step by step; more fragile if the page structure changes.
Example:/html/body/div[1]/form/input
- Relative XPath - starts from any element in the DOM, more stable and recommended.
Example://input[@id='username']
XPath Syntax Basics
//tagname[@attribute='value']
→ find a tag by attribute//tagname[text()='text']
→ find a tag with exact text//tagname[contains(@attribute,'partial')]
→ partial match//div[@class='container']//a
→ nested elements
XPath Code Examples
// absolute example
driver.findElement(By.xpath("/html/body/div/form/input")).sendKeys("hello");
// relative example
driver.findElement(By.xpath("//input[@id='username']")).sendKeys("admin");
// contains()
driver.findElement(By.xpath("//button[contains(text(),'Login')]")).click();
// text()
driver.findElement(By.xpath("//h1[text()='Dashboard']")).isDisplayed();
Best Practices
- Use relative XPaths whenever possible
- Prefer unique attributes (id, name, data-*)
- Combine multiple attributes if needed:
//button[@type='submit' and contains(text(),'Login')]
- Avoid deep absolute paths since they break easily with minor UI changes
Sample Practice
Try finding elements on the OrangeHRM demo:
- Username input:
//input[@id='txtUsername']
- Password input:
//input[@id='txtPassword']
- Login button:
//input[@id='btnLogin']
What is the Actions Class?
The Selenium Actions
class helps you handle advanced user interactions such as mouse hover, drag and drop, double click, right click, and more. These are often needed for modern web applications with dynamic behavior.
Common Actions Supported
- Mouse hover
- Click and hold
- Double click
- Right click (context click)
- Drag and drop
- Keyboard actions (like pressing keys)
How to Use the Actions Class
import org.openqa.selenium.interactions.Actions;
WebDriver driver = new ChromeDriver();
Actions actions = new Actions(driver);
WebElement menu = driver.findElement(By.id("menu"));
actions.moveToElement(menu).perform(); // mouse hover
actions.contextClick(menu).perform(); // right click
actions.doubleClick(menu).perform(); // double click
Drag and Drop Example
WebElement source = driver.findElement(By.id("draggable"));
WebElement target = driver.findElement(By.id("droppable"));
actions.dragAndDrop(source, target).perform();
Best Practices
- Always chain
.perform()
at the end of an Actions chain - Make sure the target elements are visible on the page before interacting
- Use waits if the element loads dynamically
- Prefer clear locators for Actions class elements
Sample Practice
Try practicing mouse hover or drag-and-drop on:
What is a Dropdown?
A dropdown (or select element) lets users choose one or more options from a list. In Selenium, dropdowns can be handled using the Select
class in Java.
Using the Select Class
Selenium provides a built-in Select
class that works with HTML <select>
tags.
Basic Example
import org.openqa.selenium.support.ui.Select;
WebElement dropdown = driver.findElement(By.id("country"));
Select select = new Select(dropdown);
// select by visible text
select.selectByVisibleText("India");
// select by index
select.selectByIndex(2);
// select by value attribute
select.selectByValue("US");
Working with Multi-select
if(select.isMultiple()) {
select.selectByVisibleText("Option1");
select.selectByVisibleText("Option2");
}
Best Practices
- Always check
isMultiple()
for multi-select dropdowns - Use waits if options load dynamically
- Avoid using hard-coded indexes if the list can change
Sample Practice
Try practicing on a sample site: Guru99 Register Demo
What is an Alert?
An alert is a small popup window that displays a message or asks for confirmation (like JavaScript alerts, confirms, or prompts). Selenium can handle alerts using its built-in Alert
interface.
Types of Alerts
- Simple alert: just shows a message and OK button
- Confirmation alert: OK and Cancel buttons
- Prompt alert: text box + OK/Cancel
Basic Example
Alert alert = driver.switchTo().alert();
// accept the alert
alert.accept();
// dismiss (if confirm box)
alert.dismiss();
// get alert text
String msg = alert.getText();
// send text to a prompt
alert.sendKeys("sample text");
Best Practices
- Always switch to alert before interacting
- Use try-catch in case alerts appear conditionally
- Check the alert message if needed with
getText()
Sample Practice
You can try practice alerts here: DemoQA Alerts
Why Waits are Important?
Web pages often load elements dynamically, so actions might fail if Selenium tries to interact before elements are ready. Waits help synchronize your tests with the application to avoid flakiness.
Types of Waits
- Implicit Wait - waits globally for every element to appear before throwing exception.
- Explicit Wait - waits for a specific condition for a specific element.
- Fluent Wait - advanced form of explicit wait with polling frequency and ignored exceptions.
Code Examples
// Implicit wait
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
// Explicit wait
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("username")));
// Fluent wait
Wait fluentWait = new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(30))
.pollingEvery(Duration.ofSeconds(5))
.ignoring(NoSuchElementException.class);
WebElement foo = fluentWait.until(driver -> driver.findElement(By.id("foo")));
Best Practices
- Prefer explicit waits over implicit waits for better control
- Never mix implicit and explicit waits together (can cause unpredictable behavior)
- Use proper timeout durations based on app behavior
- Log when waits time out for easier debugging
Sample Practice
Try testing waits on dynamic elements at: Herokuapp Dynamic Loading
What is TestNG?
TestNG is a popular testing framework for Java that makes it easier to organize, execute, and report Selenium tests. It supports annotations, parallel execution, groups, priorities, and data-driven testing.
Why use TestNG with Selenium?
- Easy test organization with annotations like @Test, @BeforeClass, @AfterClass
- Generates built-in reports
- Supports parallel test execution
- Flexible configuration via XML
- Integration with build tools (Maven, Jenkins)
Basic TestNG Example
import org.testng.annotations.Test;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.AfterClass;
public class LoginTest {
@BeforeClass
public void setup() {
System.out.println("Open Browser");
}
@Test
public void login() {
System.out.println("Perform Login");
}
@AfterClass
public void tearDown() {
System.out.println("Close Browser");
}
}
TestNG XML Configuration
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="MySuite">
<test name="MyTest">
<classes>
<class name="LoginTest"/>
</classes>
</test>
</suite>
Best Practices
- Keep TestNG XML files in a separate folder (e.g., testng.xml in resources)
- Use descriptive group names for easier test filtering
- Integrate TestNG reports with Jenkins or extent reports
Sample Practice
You can practice running TestNG tests in Eclipse or IntelliJ by installing the TestNG plugin from the marketplace.
What is DataProvider?
DataProvider is a feature in TestNG that allows you to pass multiple sets of data to a single test method. This helps build data-driven tests without duplicating code.
Why use DataProvider?
- Run the same test with multiple data sets
- Separate data from test logic
- Support for parameterization of tests
Basic DataProvider Example
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class LoginDataTest {
@DataProvider(name = "loginData")
public Object[][] getData() {
return new Object[][] {
{"admin", "admin123"},
{"user", "user123"},
{"guest", "guest123"}
};
}
@Test(dataProvider = "loginData")
public void loginTest(String username, String password) {
System.out.println("Logging in with: " + username + " / " + password);
}
}
Best Practices
- Keep your DataProviders in a separate utility class for reusability
- Use meaningful names for DataProviders
- Combine with Excel or JSON files for more complex data-driven tests
Sample Practice
Practice creating a DataProvider for a login test on: OrangeHRM Demo
What is Parameterization?
Parameterization means passing different input values to your test scripts without hardcoding them, making your tests reusable and data-driven.
How to do Parameterization in Selenium?
- Using TestNG
<parameter>
tags in XML - Using TestNG DataProviders
- Reading data from Excel, JSON, CSV, or databases
Example with TestNG XML Parameters
// testng.xml
<parameter name="username" value="admin"/>
// Java
@Parameters({"username"})
@Test
public void testLogin(String user) {
System.out.println("Logging in with: " + user);
}
Example from Excel (Apache POI)
// simplified example
FileInputStream fis = new FileInputStream("testdata.xlsx");
Workbook wb = WorkbookFactory.create(fis);
Sheet sh = wb.getSheet("Login");
String username = sh.getRow(0).getCell(0).getStringCellValue();
Best Practices
- Use external data files to avoid hardcoding
- Keep parameter names consistent across XML and Java
- Handle missing or null data gracefully
Sample Practice
Try parameterizing login data for OrangeHRM Demo with different usernames and passwords.
What is POM?
The Page Object Model (POM) is a design pattern in Selenium that helps you maintain clean, reusable, and scalable test code by separating page locators and actions into dedicated classes.
Why use POM?
- Improves code readability and reusability
- Makes tests easier to maintain when the UI changes
- Supports cleaner separation of concerns
Basic POM Example
Let’s automate a simple login page.
// LoginPage.java
public class LoginPage {
WebDriver driver;
@FindBy(id="username") WebElement usernameField;
@FindBy(id="password") WebElement passwordField;
@FindBy(id="loginBtn") WebElement loginButton;
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public void login(String user, String pass) {
usernameField.sendKeys(user);
passwordField.sendKeys(pass);
loginButton.click();
}
}
Then in your test class:
// LoginTest.java
LoginPage lp = new LoginPage(driver);
lp.login("admin", "admin123");
Best Practices
- Use meaningful page object class names
- Keep locators and actions together in the page class
- Use the PageFactory to initialize elements
- Follow a consistent package structure (e.g.,
pages
,tests
)
Sample Practice
Try implementing POM for the login flow of OrangeHRM Demo.
What is a Hybrid Framework?
A Hybrid Framework combines multiple automation frameworks such as Data-Driven, Keyword-Driven, and Page Object Model. It takes the best features of each and creates a flexible, scalable, and reusable structure for automation.
Why use a Hybrid Framework?
- Better maintainability by separating data, keywords, and locators
- Supports reusability through Page Object classes
- Easy to scale for large projects
- Non-programmers can contribute using keywords
How does it work?
Typically, a Hybrid Framework has:
- Test scripts that call reusable methods (Page Objects)
- External data sources (Excel, JSON, XML) for data-driven testing
- Keyword files for business actions
- TestNG or JUnit for execution control
- Reporting tools like ExtentReports for results
Example Folder Structure
/tests
LoginTest.java
/pages
LoginPage.java
/keywords
KeywordLibrary.java
/utils
ExcelUtils.java
/testdata
LoginData.xlsx
/reports
extent-report.html
Best Practices
- Keep page objects, test data, keywords, and utilities in separate folders
- Version control the framework with Git
- Write a framework setup guide for your team
Sample Practice
Try building a hybrid framework combining DataProvider, POM, and reusable keyword methods for: OrangeHRM Demo.
What is BDD?
Behavior Driven Development (BDD) is a software development approach where test scenarios are written in plain English using a language called Gherkin. BDD bridges the gap between business, development, and testing teams by making test cases more readable and collaborative.
Why use Cucumber with Selenium?
- Uses plain language steps: Given, When, Then
- Improves collaboration with non-technical stakeholders
- Separates feature files (requirements) from step definitions (code)
- Integrates easily with Java Selenium frameworks
Sample Gherkin Feature File
Feature: Login functionality
Scenario: Successful login
Given user is on login page
When user enters valid credentials
Then user should be redirected to the dashboard
Sample Step Definition
@Given("user is on login page")
public void user_is_on_login_page() {
driver.get("https://opensource-demo.orangehrmlive.com/");
}
@When("user enters valid credentials")
public void user_enters_valid_credentials() {
driver.findElement(By.id("txtUsername")).sendKeys("Admin");
driver.findElement(By.id("txtPassword")).sendKeys("admin123");
driver.findElement(By.id("btnLogin")).click();
}
@Then("user should be redirected to the dashboard")
public void user_should_see_dashboard() {
Assert.assertTrue(driver.findElement(By.id("welcome")).isDisplayed());
}
Best Practices
- Keep feature files simple and business-readable
- Reuse step definitions to avoid duplication
- Use hooks for setup and teardown code
- Use page objects inside your step definitions for cleaner code
Sample Practice
Try writing a login feature and step definition for OrangeHRM Demo using Cucumber and Selenium.
What is Jenkins?
Jenkins is an open-source continuous integration and continuous delivery (CI/CD) tool that helps automate building, testing, and deploying software. It integrates perfectly with Selenium frameworks to automatically run your automated tests.
Why use Jenkins with Selenium?
- Schedule tests automatically on code changes
- Run tests on multiple environments (Windows, Linux, cloud)
- Generate detailed reports after test runs
- Support for plugins like TestNG and Allure reports
How to Set Up Jenkins for Selenium
- Download Jenkins from jenkins.io
- Install Java JDK if not installed
- Run Jenkins and open its dashboard on
http://localhost:8080
- Install suggested plugins
- Create a new job (Freestyle or Pipeline)
- Configure Git repository and build steps (Maven commands, etc.)
- Save and trigger builds
Sample Maven Command for Jenkins
mvn clean test
Best Practices
- Keep Jenkins updated to the latest LTS version
- Use pipeline scripts (Jenkinsfile) for better control
- Store sensitive credentials securely with Jenkins Credentials plugin
- Archive reports as artifacts for later analysis
Sample Practice
Try configuring a Jenkins Freestyle job to run your Selenium Maven project after each code commit from GitHub.
Why use GitHub with Selenium?
GitHub is a powerful version control and collaboration platform that helps you store, share, and manage your Selenium automation code with teams. It allows you to track changes, manage branches, and integrate with CI/CD tools like Jenkins.
Benefits of Using GitHub
- Easy code sharing with team members
- Change tracking with commit history
- Branching for parallel development and testing
- Integration with Jenkins for automated builds
- Open source and widely adopted in the industry
How to Use GitHub with Selenium
- Create a free account on GitHub
- Initialize a new repository for your Selenium project
- Use
git
commands or GitHub Desktop to push your project code - Share the repo link with your team
- Integrate your repository in Jenkins under "Source Code Management"
Sample Git Commands
git init
git add .
git commit -m "first selenium project"
git remote add origin https://github.com/yourusername/yourrepo.git
git push -u origin main
Best Practices
- Use meaningful commit messages
- Follow branching strategies (e.g., feature, dev, main branches)
- Protect your main branch with PR (Pull Request) reviews
- Use .gitignore to exclude temporary files or logs
Sample Practice
Create a GitHub repo, push your Selenium Maven project, and link it to a Jenkins build pipeline.
What is Maven?
Maven is a popular build automation and dependency management tool for Java projects. It makes it easy to manage Selenium libraries, build processes, and test execution from a single configuration file.
Why use Maven with Selenium?
- Automatically downloads Selenium dependencies from a central repository
- Supports project builds with a single command
- Easy to integrate with CI tools like Jenkins
- Uses a simple
pom.xml
to manage everything
Installing Maven
- Download Maven from maven.apache.org
- Unzip and add Maven’s
bin
directory to your system PATH - Verify by running
mvn -v
in your terminal
Sample pom.xml
for Selenium
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>seleniumproject</artifactId>
<version>1.0</version>
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.10.0</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
How to Run Tests with Maven
Use the following command to execute tests:
mvn clean test
Best Practices
- Always update dependencies to stable versions
- Keep your
pom.xml
clean and organized - Use Maven profiles to manage different environments (QA, staging, prod)
Sample Practice
Create a Maven project for Selenium and configure it to run TestNG tests automatically.
Why is Reporting Important?
Reports help you visualize test execution results, identify failures quickly, and share outcomes with your team or stakeholders. Selenium alone does not generate rich reports, so you typically integrate it with reporting tools.
Popular Reporting Tools
- ExtentReports
- Allure Reports
- TestNG HTML Reports (built-in)
ExtentReports Setup Example
// Maven dependency
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>5.1.0</version>
</dependency>
// Java example
ExtentReports extent = new ExtentReports();
ExtentSparkReporter spark = new ExtentSparkReporter("target/Spark.html");
extent.attachReporter(spark);
ExtentTest test = extent.createTest("LoginTest");
test.pass("Login test passed");
extent.flush();
Best Practices
- Save reports with timestamps to distinguish runs
- Integrate screenshots for failures
- Use consistent naming for test cases in reports
- Keep reports under version control if needed
Sample Practice
Try setting up ExtentReports for your Selenium TestNG project to generate detailed reports with pass/fail screenshots.
Project Overview
Let’s put everything together in a simple Selenium Maven + TestNG project following POM design pattern. We’ll automate login for the OrangeHRM demo site as a practical example.
Project Structure
/src
/main
/java
/pages
LoginPage.java
/tests
LoginTest.java
/utils
ExcelUtils.java
/testdata
LoginData.xlsx
/testng.xml
LoginPage.java (Page Object)
public class LoginPage {
WebDriver driver;
@FindBy(id="txtUsername") WebElement username;
@FindBy(id="txtPassword") WebElement password;
@FindBy(id="btnLogin") WebElement loginButton;
public LoginPage(WebDriver driver) {
this.driver = driver;
PageFactory.initElements(driver, this);
}
public void login(String user, String pass) {
username.sendKeys(user);
password.sendKeys(pass);
loginButton.click();
}
}
LoginTest.java
public class LoginTest {
WebDriver driver;
LoginPage login;
@BeforeClass
public void setup() {
driver = new ChromeDriver();
driver.get("https://opensource-demo.orangehrmlive.com/");
login = new LoginPage(driver);
}
@Test
public void testLogin() {
login.login("Admin", "admin123");
Assert.assertTrue(driver.findElement(By.id("welcome")).isDisplayed());
}
@AfterClass
public void tearDown() {
driver.quit();
}
}
testng.xml
<suite name="OrangeHRMSuite">
<test name="LoginTest">
<classes>
<class name="tests.LoginTest"/>
</classes>
</test>
</suite>
Best Practices
- Follow proper naming conventions for classes and packages
- Keep page locators separate from test logic
- Version control the entire project with GitHub
- Use Maven to manage dependencies and builds
- Integrate reporting with ExtentReports for results
Next Steps
Enhance this project by adding DataProviders, external data sources, and Jenkins for CI/CD.