Selenium
Set up Selenium WebDriver for browser testing and integrate test results with TestKase.
Overview
Selenium is an open-source browser automation framework that supports multiple programming languages including Java, Python, JavaScript, and C#. It uses the WebDriver protocol to control browsers programmatically, making it the most widely adopted tool for end-to-end web testing.
Selenium itself does not produce test reports — it relies on the test runner you pair it with (JUnit, TestNG, pytest, etc.). To integrate with TestKase, use:
--format junitwhen running Selenium tests with JUnit (Java) or pytest (Python)--format testngwhen running Selenium tests with TestNG (Java)
Prerequisites
- Java: Java 11 or later, Maven 3.6+
- Python: Python 3.8 or later, pip
- Node.js: Node.js 18 or later (for JavaScript bindings)
- Browser drivers: ChromeDriver, GeckoDriver (Firefox), or EdgeDriver matching your installed browser version
- A TestKase account with a project, test cycle, and Automation IDs configured on your test cases
Installation
Java (Maven)
Add the following dependencies to your pom.xml:
<dependencies>
<!-- Selenium WebDriver -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.18.1</version>
</dependency>
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<!-- WebDriverManager (auto-manages browser drivers) -->
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
</dependencies>Python
pip install selenium pytestProject Setup
Java — Maven Project Structure
my-selenium-project/
├── pom.xml
└── src/
└── test/
└── java/
└── com/
└── example/
├── LoginTest.java
└── SearchTest.javaYour pom.xml should include the Maven Surefire Plugin (included by default in most Maven projects)
which generates JUnit XML reports in target/surefire-reports/:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
</plugin>
</plugins>
</build>Python — Project Structure
my-selenium-project/
├── requirements.txt
├── conftest.py
└── tests/
├── test_login.py
└── test_search.pyrequirements.txt:
selenium>=4.18.0
pytest>=8.0.0Writing Tests
Java — JUnit 5 Test Class
package com.example;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;
import static org.junit.jupiter.api.Assertions.*;
public class LoginTest {
private WebDriver driver;
private WebDriverWait wait;
@BeforeEach
void setUp() {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
wait = new WebDriverWait(driver, Duration.ofSeconds(10));
driver.get("https://example.com/login");
}
@AfterEach
void tearDown() {
if (driver != null) {
driver.quit();
}
}
@Test
@DisplayName("[48271] testValidLogin")
void testValidLogin() {
driver.findElement(By.id("username")).sendKeys("testuser");
driver.findElement(By.id("password")).sendKeys("password123");
driver.findElement(By.id("login-btn")).click();
WebElement dashboard = wait.until(
ExpectedConditions.presenceOfElementLocated(By.id("dashboard"))
);
assertTrue(dashboard.isDisplayed());
}
@Test
@DisplayName("[48272] testInvalidLogin")
void testInvalidLogin() {
driver.findElement(By.id("username")).sendKeys("invalid");
driver.findElement(By.id("password")).sendKeys("wrong");
driver.findElement(By.id("login-btn")).click();
WebElement error = wait.until(
ExpectedConditions.presenceOfElementLocated(By.className("error-message"))
);
assertEquals("Invalid credentials", error.getText());
}
}Each test includes a 5-digit Automation ID in its @DisplayName annotation using square brackets.
The @testkase/reporter CLI extracts these IDs using the regex \[(\d{5})\]. For the tests above:
48271→ linked to the "valid login" test case in TestKase48272→ linked to the "invalid login" test case in TestKase
Python — pytest Test File
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class TestLogin:
def setup_method(self):
self.driver = webdriver.Chrome()
self.driver.get("https://example.com/login")
self.wait = WebDriverWait(self.driver, 10)
def teardown_method(self):
if self.driver:
self.driver.quit()
def test_valid_login(self):
self.driver.find_element(By.ID, "username").send_keys("testuser")
self.driver.find_element(By.ID, "password").send_keys("password123")
self.driver.find_element(By.ID, "login-btn").click()
dashboard = self.wait.until(
EC.presence_of_element_located((By.ID, "dashboard"))
)
assert dashboard.is_displayed()
def test_invalid_login(self):
self.driver.find_element(By.ID, "username").send_keys("invalid")
self.driver.find_element(By.ID, "password").send_keys("wrong")
self.driver.find_element(By.ID, "login-btn").click()
error = self.wait.until(
EC.presence_of_element_located((By.CLASS_NAME, "error-message"))
)
assert error.text == "Invalid credentials"Embed 5-digit Automation IDs in your test names using square brackets so they appear in the JUnit XML output.
For pytest, use @pytest.mark or include the ID in the test's parametrize label:
[48271]→ linked to the "valid login" test case in TestKase[48272]→ linked to the "invalid login" test case in TestKase
Running Tests
Java (Maven)
mvn testJUnit XML reports are generated automatically in target/surefire-reports/. Each test class
produces a file named TEST-<className>.xml (e.g., TEST-com.example.LoginTest.xml).
Python (pytest)
pytest --junitxml=test-results/junit.xmlThis produces a single JUnit XML file at test-results/junit.xml.
TestKase Integration
After running your tests and generating the results file, use the @testkase/reporter CLI
to push results to TestKase.
Java (JUnit XML from Maven Surefire)
npx @testkase/reporter report \
--token $TESTKASE_PAT \
--project-id PRJ-1 \
--org-id 1173 \
--cycle-id TCYCLE-5 \
--format junit \
--results-file "target/surefire-reports/TEST-*.xml"--cycle-id is optional. If not provided, results are reported to TCYCLE-1 — the master test cycle for the project.
Python (JUnit XML from pytest)
npx @testkase/reporter report \
--token $TESTKASE_PAT \
--project-id PRJ-1 \
--org-id 1173 \
--cycle-id TCYCLE-5 \
--format junit \
--results-file test-results/junit.xmlUse --dry-run --verbose the first time to verify that your test names match the Automation IDs
you set in TestKase. This helps catch naming mismatches before pushing real results.
Automation ID Mapping
The reporter extracts 5-digit Automation IDs from test names using the [XXXXX] bracket pattern:
| Runner | Where to Embed the ID | Example |
|---|---|---|
| Java (JUnit 5) | @DisplayName annotation | @DisplayName("[48271] testValidLogin") |
| Java (TestNG) | @Test(description = "...") | @Test(description = "[48271] testValidLogin") |
| Python (pytest) | Test docstring or parametrize ID | """[48271] Valid login test""" |
| JavaScript (Mocha/Jest) | it() or test() name | test('[48271] should authenticate user', ...) |
Generate Automation IDs in TestKase first, then embed them in your test names. Use --dry-run to
verify which [XXXXX] IDs the reporter extracts from your results file.
Complete Example
This end-to-end example shows the full flow for a Java Selenium project with JUnit 5.
1. Create the Test
package com.example;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;
import static org.junit.jupiter.api.Assertions.*;
public class SearchTest {
private WebDriver driver;
private WebDriverWait wait;
@BeforeEach
void setUp() {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
wait = new WebDriverWait(driver, Duration.ofSeconds(10));
}
@AfterEach
void tearDown() {
if (driver != null) {
driver.quit();
}
}
@Test
@DisplayName("[48271] testSearchReturnsResults")
void testSearchReturnsResults() {
driver.get("https://example.com");
driver.findElement(By.id("search-input")).sendKeys("selenium");
driver.findElement(By.id("search-btn")).click();
WebElement results = wait.until(
ExpectedConditions.presenceOfElementLocated(By.id("search-results"))
);
assertTrue(results.isDisplayed());
}
}2. Set the Automation ID in TestKase
In your TestKase project, generate an Automation ID (e.g., 48271) on the corresponding test case, then
embed it in your test's @DisplayName annotation: @DisplayName("[48271] testSearchReturnsResults")
3. Run the Tests
mvn test4. Verify with Dry Run
npx @testkase/reporter report \
--token $TESTKASE_PAT \
--project-id PRJ-1 \
--org-id 1173 \
--cycle-id TCYCLE-5 \
--format junit \
--results-file "target/surefire-reports/TEST-com.example.SearchTest.xml" \
--dry-run --verbose5. Push Results
Remove the --dry-run flag to push results to TestKase:
npx @testkase/reporter report \
--token $TESTKASE_PAT \
--project-id PRJ-1 \
--org-id 1173 \
--cycle-id TCYCLE-5 \
--format junit \
--results-file "target/surefire-reports/TEST-com.example.SearchTest.xml"Troubleshooting
WebDriver not found
org.openqa.selenium.SessionNotCreatedException: Could not start a new session.Cause: The browser driver (ChromeDriver, GeckoDriver) is not installed or not on your PATH.
Fix: Use WebDriverManager to automatically download and configure the correct driver version:
// Add to your test setup:
WebDriverManager.chromedriver().setup();Or install drivers manually and add them to your system PATH.
Stale element references
org.openqa.selenium.StaleElementReferenceException: stale element referenceCause: The DOM element was modified or removed after you located it.
Fix: Use WebDriverWait with ExpectedConditions to wait for elements to be present or visible
before interacting with them:
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement element = wait.until(
ExpectedConditions.presenceOfElementLocated(By.id("my-element"))
);JUnit XML not generated
Cause: The Maven Surefire Plugin is not configured or the test phase was skipped.
Fix: Ensure the Surefire Plugin is included in your pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
</plugin>Verify that target/surefire-reports/ contains XML files after running mvn test. If the
directory is empty, check that your test classes follow the Surefire naming convention
(*Test.java, Test*.java, or *Tests.java).