🌐 US-Proxy
class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
Skip to content

seleniumboot/selenium-boot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

155 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Selenium Boot

A Zero-Boilerplate, Production-Ready Framework for Java QA Automation

Maven Central License

Documentation Β· Sample Project Β· Changelog


AI-powered test authoring for Selenium Boot users Use seleniumboot-mcp to let Claude / GitHub Copilot control a real browser, record your session, and generate ready-to-run Selenium Boot test code β€” TestNG, JUnit 5, Page Object, Gherkin, or C# NUnit.

pip install seleniumboot-mcp

PyPI Β· GitHub Β· 76 tools Β· self-healing locators Β· codegen for Java / Python / C# / Playwright


Overview

Selenium Boot is a zero-boilerplate, production-ready automation framework for Java Selenium, inspired by the philosophy of Spring Boot.

It eliminates repetitive boilerplate by providing sensible defaults, a standardized project structure, and a convention-over-configuration approach β€” while keeping Selenium fully visible and accessible.


What You Get Out of the Box

  • Automatic WebDriver lifecycle management (no setup/teardown boilerplate)
  • YAML-based configuration with environment profile switching
  • Parallel execution with thread-safe driver isolation
  • Smart explicit waits via WaitEngine β€” no more Thread.sleep()
  • Automatic retry for flaky tests via @Retryable
  • Screenshot capture on failure, embedded in report
  • Advanced HTML report β€” pass rate gauge, donut chart, slowest tests, step timeline, dark mode
  • BasePage β€” wait-backed click, type, getText, isDisplayed, iFrame helpers, file upload
  • SmartLocator β€” tries multiple By strategies in order, returns first visible element
  • @PreCondition β€” session-aware pre-conditions with automatic cookie + localStorage caching
  • ConsoleErrorCollector β€” capture JS console errors (Chrome via logs, Firefox via shim)
  • DownloadManager β€” poll download directory, handle partial files
  • StepLogger β€” named test steps with timestamps and per-step screenshots
  • API testing β€” BaseApiTest for pure API tests; fluent ApiClient with auth, schema validation, JSONPath; hybrid UI + API tests in the same suite
  • Accessibility assertions β€” accessibility().withTags("wcag2a","wcag21aa").withLevel(Impact.SERIOUS).run() β€” axe-core bundled in JAR, no extra dependency; scoped scans, exclude selectors, fluent Impact level filter
  • Plugin system β€” custom browser providers, report adapters, lifecycle hooks via Java SPI
  • CI-ready β€” auto-detects GitHub Actions, Jenkins, CircleCI; forces headless, emits JUnit XML

Getting Started

Prerequisites

  • Java 17+
  • Maven 3.8+
  • Chrome or Firefox installed

No WebDriver binaries required β€” Selenium Manager handles it automatically.


Step 1: Add the Dependency

Add to your pom.xml:

<dependency>
    <groupId>io.github.seleniumboot</groupId>
    <artifactId>selenium-boot</artifactId>
    <version>3.0.0</version>
</dependency>

Also add the Surefire plugin so mvn test discovers TestNG tests:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>3.2.5</version>
        </plugin>
    </plugins>
</build>

Step 2: Create the Configuration File

Create selenium-boot.yml at your project root (same level as pom.xml):

execution:
  mode: local           # local | remote
  baseUrl: https://example.com
  parallel: methods     # none | methods | classes
  threadCount: 4
  maxActiveSessions: 4

browser:
  name: chrome          # chrome | firefox
  headless: false
  lifecycle: per-test   # per-test (default) | per-suite
  captureConsoleErrors: true
  arguments:
    - --start-maximized
    - --disable-notifications

retry:
  enabled: true
  maxAttempts: 2

timeouts:
  explicit: 10          # seconds β€” used by WaitEngine
  pageLoad: 30          # seconds

That is the only configuration file needed. All fields have defaults β€” start with the minimum:

execution:
  mode: local
  baseUrl: https://example.com

browser:
  name: chrome

Step 3: Project Structure

your-project/
β”œβ”€β”€ pom.xml
β”œβ”€β”€ selenium-boot.yml
└── src/
    └── test/
        └── java/
            └── com/yourcompany/
                β”œβ”€β”€ conditions/
                β”‚   └── AppConditions.java
                β”œβ”€β”€ pages/
                β”‚   └── LoginPage.java
                └── tests/
                    └── LoginTest.java

Step 4: Create a Page Object

Extend the framework's built-in BasePage β€” it provides wait-backed interaction helpers out of the box:

package com.yourcompany.pages;

import com.seleniumboot.test.BasePage;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

public class LoginPage extends BasePage {

    private final By usernameField = By.id("username");
    private final By passwordField = By.id("password");
    private final By loginButton   = By.id("login-btn");

    public LoginPage(WebDriver driver) {
        super(driver);
    }

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

BasePage provides: click, type, getText, getAttribute, isDisplayed, withinFrame, withinFrameIndex, upload. All backed by WaitEngine β€” no manual waits needed.


Step 5: Write Your Tests

Extend BaseTest β€” that's all the setup needed:

package com.yourcompany.tests;

import com.seleniumboot.steps.StepLogger;
import com.seleniumboot.test.BaseTest;
import com.yourcompany.pages.LoginPage;
import org.testng.annotations.Test;

import static org.testng.Assert.assertTrue;

public class LoginTest extends BaseTest {

    @Test
    public void loginWithValidCredentials() {
        StepLogger.step("Open login page");
        open();

        StepLogger.step("Enter credentials and submit", true);
        new LoginPage(getDriver()).login("admin", "password123");

        assertTrue(getDriver().getCurrentUrl().contains("/dashboard"));
    }
}

Rules:

  • Always extend BaseTest
  • Never instantiate or quit WebDriver manually β€” the framework manages it
  • Use getDriver() to access the current thread's driver instance
  • Use open() to navigate to baseUrl, or open("/path") for a sub-path

Step 6: Run Tests

mvn test

That's it. Selenium Boot handles driver creation, parallel execution, retries, screenshots, and report generation automatically.


Step 7: View the Report

After execution, open the HTML report:

target/selenium-boot-report.html

The report includes:

  • Pass rate gauge with colour coding
  • Donut chart β€” pass/fail/skip distribution
  • Per-test execution time and retry badges
  • Step timeline per test
  • Failure screenshots (base64 embedded, click to expand)
  • Dark mode toggle

@PreCondition β€” Session Caching

Eliminate repeated login boilerplate. Declare a condition once, cache the session, reuse it across tests:

// 1. Define conditions
public class AppConditions extends BaseConditions {

    @ConditionProvider("loginAsAdmin")
    public void loginAsAdmin() {
        open("/");
        new LoginPage(getDriver()).login("admin", "secret");
    }
}
// 2. Register via SPI
src/test/resources/META-INF/services/com.seleniumboot.precondition.BaseConditions
β†’ com.yourcompany.conditions.AppConditions
// 3. Use in tests
@Test
@PreCondition("loginAsAdmin")
public void viewDashboard() {
    open("/dashboard");  // session already established β€” no re-login
}

@Test
@PreCondition("loginAsAdmin")
public void editProfile() {
    open("/profile");    // session restored from cache
}

Cache is per-thread β€” safe for parallel execution. On retry, cache is invalidated and the condition re-runs fresh.


API Testing

Selenium Boot supports pure API tests and hybrid UI + API tests β€” same framework, same config, same HTML report.

Pure API Tests

Extend BaseApiTest instead of BaseTest. No browser is launched.

public class UserApiTest extends BaseApiTest {

    @Test
    public void getUserById() {
        ApiClient.get("https://api.example.com/users/1")
                .send()
                .assertStatus(200)
                .assertJson("$.name", "John Doe");
    }
}

ApiClient β€” Fluent HTTP Client

// GET
ApiClient.get("/api/users").send();

// POST with body
ApiClient.post("/api/users")
        .body(Map.of("name", "Alice", "email", "alice@example.com"))
        .send()
        .assertStatus(201);

// Custom header
ApiClient.get("/api/orders")
        .header("X-Request-ID", "abc123")
        .send();

// Different base URL for one request
ApiClient.to("https://other-service.com").get("/health").send();

Configure the default base URL in selenium-boot.yml:

api:
  baseUrl: https://api.example.com
  timeoutSeconds: 30
  logBody: false   # set true to include body in step timeline

ApiResponse β€” Assertions and Extraction

ApiResponse res = ApiClient.get("/api/users/1").send();

res.assertStatus(200);
res.assertBodyContains("Alice");
res.assertJson("$.name", "Alice");

// Extract values
String name  = res.json("$.name");
int    id    = res.json("$.id", Integer.class);
User   user  = res.asObject(User.class);

// Fluent chaining
res.assertStatus(200)
   .assertJson("$.name", "Alice")
   .assertSchema("schemas/user.json");

Authentication

Bearer token:

ApiClient.get("/api/me")
        .auth(ApiAuth.bearerToken("my-token"))
        .send();

Basic auth:

ApiClient.get("/api/admin")
        .auth(ApiAuth.basicAuth("user", "pass"))
        .send();

Set auth once for the entire suite β€” all requests use it automatically:

@BeforeSuite
public void authenticate() {
    ApiResponse login = ApiClient.post("/api/auth/login")
            .body(Map.of("username", "admin", "password", "pass"))
            .send();
    ApiClient.setGlobalAuth(ApiAuth.bearerToken(login.json("$.token")));
}

OAuth2 client credentials β€” token fetched and cached automatically:

ApiClient.setGlobalAuth(ApiAuth.oauth2(
    "https://auth.example.com/token",
    System.getenv("CLIENT_ID"),
    System.getenv("CLIENT_SECRET")
));

Config-based auth with @UseAuth β€” define strategies in YAML, apply per test:

api:
  auth:
    adminToken:
      type: bearer
      token: ${ADMIN_TOKEN}       # resolved from env var
    serviceAccount:
      type: oauth2
      tokenUrl: https://auth.example.com/token
      clientId: ${CLIENT_ID}
      clientSecret: ${CLIENT_SECRET}
@Test
@UseAuth("adminToken")
public void createUser() {
    ApiClient.post("/api/users").body(...).send().assertStatus(201);
}

Schema Validation

Validate response structure against a JSON Schema file:

ApiClient.get("/api/users/1")
        .send()
        .assertStatus(200)
        .assertSchema("schemas/user.json");

Place schema files under src/test/resources/schemas/. Requires one additional dependency:

<dependency>
    <groupId>com.networknt</groupId>
    <artifactId>json-schema-validator</artifactId>
    <version>1.4.3</version>
</dependency>

Hybrid UI + API Tests

Mix API calls and browser interactions in the same test via apiClient() in BaseTest:

public class CheckoutTest extends BaseTest {

    @Test
    public void placeOrder() {
        // Set up via API (fast, no UI navigation)
        String orderId = apiClient().post("/api/orders")
                .body(Map.of("productId", 42, "qty", 1))
                .send()
                .assertStatus(201)
                .json("$.orderId");

        // Verify in the UI
        open("/orders/" + orderId);
        Assert.assertEquals(getText(By.id("status")), "Pending");
    }
}

Scenario & Suite Context

Share state within a test or across tests without static fields:

// ScenarioContext β€” lives for one test, auto-cleared after
ctx().set("token", loginRes.json("$.token"));
String token = ctx().get("token");

// SuiteContext β€” survives between tests, thread-safe
suiteCtx().set("createdUserId", res.json("$.id"));   // in test 1
String userId = suiteCtx().get("createdUserId");      // in test 2

WaitEngine Reference

WaitEngine uses the timeouts.explicit value from your config. Never use Thread.sleep().

import com.seleniumboot.wait.WaitEngine;
import org.openqa.selenium.By;

WebElement el  = WaitEngine.waitForVisible(By.id("submit-btn"));
WebElement btn = WaitEngine.waitForClickable(By.cssSelector(".next-btn"));
WaitEngine.waitForTitle("Dashboard");
WaitEngine.waitForUrlContains("/dashboard");
WaitEngine.waitForText(By.id("status"), "Complete");
WaitEngine.waitForPageLoad();

Retry Reference

Add @Retryable to any @Test method to enable retry on failure. The number of retries is controlled by retry.maxAttempts in your config. Retries can be globally disabled with retry.enabled: false.

@Retryable
@Test
public void flakyTest() {
    // retried up to maxAttempts times if it fails
}

Remote Execution (Selenium Grid)

Update selenium-boot.yml:

execution:
  mode: remote
  baseUrl: https://example.com
  gridUrl: http://localhost:4444/wd/hub
  parallel: methods
  threadCount: 4

browser:
  name: chrome
  headless: true

No code changes required β€” just config.


Environment Profiles

Name your config files by environment and activate with a system property:

selenium-boot.yml          # default
selenium-boot-staging.yml  # staging profile
selenium-boot-prod.yml     # prod profile
mvn test -Denv=staging

Extending the Framework

Selenium Boot exposes four extension points. All support both Java SPI (automatic discovery) and programmatic registration.

Custom Driver Provider

public class EdgeDriverProvider implements NamedDriverProvider {
    @Override public String browserName() { return "edge"; }
    @Override public WebDriver createDriver() { return new EdgeDriver(); }
}

Register via SPI (META-INF/services/com.seleniumboot.driver.NamedDriverProvider) or:

DriverProviderRegistry.register(new EdgeDriverProvider());

Custom Report Adapter

public class SlackReportAdapter implements ReportAdapter {
    @Override public String getName() { return "slack"; }
    @Override public void generate(File metricsJson) { /* post to Slack */ }
}

Register via SPI (META-INF/services/com.seleniumboot.reporting.ReportAdapter) or:

ReportAdapterRegistry.register(new SlackReportAdapter());

Lifecycle Hooks

public class TimingHook implements ExecutionHook {
    @Override
    public void onTestFailure(String testId, Throwable cause) {
        alerting.notify(testId, cause.getMessage());
    }
}

Available events: onSuiteStart, onSuiteEnd, onTestStart, onTestEnd, onTestFailure.

Plugin System

Combine driver providers, report adapters, and hooks into a single deployable unit:

public class MyPlugin implements SeleniumBootPlugin {
    @Override public String getName() { return "my-plugin"; }
    @Override public void onLoad(SeleniumBootConfig config) {
        ReportAdapterRegistry.register(new SlackReportAdapter());
    }
}

Declare minimum required framework version to prevent incompatibility:

@Override public String minFrameworkVersion() { return "0.8.0"; }

CI/CD Integration

Selenium Boot auto-detects CI environments and applies sensible defaults β€” no YAML changes required.

  • browser.headless is forced to true
  • threadCount is auto-derived from available CPU cores
  • Docker/container flags (--no-sandbox, --disable-dev-shm-usage) are auto-applied to Chrome
  • JUnit XML written to target/surefire-reports/TEST-SeleniumBoot.xml on every run

Build Quality Gates

ci:
  failOnPassRateBelow: 80   # fail build if pass rate drops below 80%
  maxFlakyTests: 3          # fail build if more than 3 tests were retried

Project Status

v3.0.0 β€” 2026-06-21

  • TestRail + Xray Integration β€” annotate any test method with @TestRailCase("C1234") or @XrayTest("PROJ-123") (both support arrays for multiple IDs); results are pushed automatically after each test completes β€” no extra code in @Test methods; TestRail results are pushed per-test immediately; Xray results are batch-imported at suite end for efficiency
  • TestRail β€” creates a named run automatically (testmanagement.testrail.autoCreateRun: true); configurable projectId, suiteId, runName; maps PASSEDβ†’1, FAILEDβ†’5, SKIPPEDβ†’Retest(4); failure message is sent as the TestRail result comment
  • Xray Cloud β€” authenticates via OAuth2 client credentials (clientId + clientSecret); uses https://xray.cloud.getxpecto.com/api/v2 endpoints; supports testPlanKey linking
  • Xray Server/DC β€” HTTP Basic auth (jiraUrl + username + password); posts to /rest/raven/1.0/import/execution; both modes use the same @XrayTest annotation
  • Zero extra dependencies β€” clients use java.net.http.HttpClient (Java 17 built-in); no OkHttp, Apache HttpClient, or Jackson required for this feature
  • Works with TestNG and JUnit 5 β€” SuiteExecutionListener + TestExecutionListener handle TestNG; SeleniumBootExtension + SeleniumBootLauncherListener handle JUnit 5

v2.6.0 β€” 2026-06-20

  • Gradle Build Support β€” testImplementation 'io.github.seleniumboot:selenium-boot:2.6.0' in build.gradle; test { useTestNG() } is all that's needed; full docs with Groovy + Kotlin DSL samples, parallel config, JUnit 5 setup, and optional-dep table; JUnitXmlReporter auto-detects Maven vs Gradle by directory layout and writes to build/test-results/test/ (Gradle) or target/surefire-reports/ (Maven); override with -Dseleniumboot.reports.dir=; FrameworkVersion now reads Implementation-Version from MANIFEST.MF (set by maven-jar-plugin and Gradle jar task) so FrameworkVersion.get() returns the correct version in both build tools

v2.5.0 β€” 2026-06-20

  • Accessibility Assertions (axe-core) β€” accessibility().withTags("wcag2a","wcag21aa").withLevel(Impact.SERIOUS).excluding("#cookie-banner").run() runs an axe-core WCAG scan on the active page; axe-core 4.10.2 bundled in the JAR β€” no CDN, no extra Maven dependency; withContext("#main-form") scopes the scan to a subtree; collect() returns raw AccessibilityResult for custom inspection; detailed AssertionError message shows rule ID, severity, fix guidance, element selector, and docs URL for every failing node; available in BaseTest and BaseJUnit5Test

v2.4.0 β€” 2026-05-19

  • Performance Assertions β€” assertPerformance().lcp().isBelow(2500).fcp().isBelow(1800).ttfb().isBelow(600).cls().isBelow(0.1) β€” Core Web Vitals via browser-native window.performance API, no extra tool needed; LCP/CLS Chrome/Edge only, others all browsers; unavailable metrics silently skipped; performance.captureOnEveryTest: true shows ⚑ metrics strip in HTML report

v2.3.0 β€” 2026-05-17

  • Test Quarantine β€” selenium-quarantine.yml committed to the repo lists tests to skip; survives fresh CI clones; plain string or structured-with-reason format; class-only entry skips all methods in the class; Cucumber support via @quarantine tag; quarantine.enabled: false disables without editing the file

v2.2.0 β€” 2026-05-12

  • External @TestData sources β€” @TestData("csv:testdata/logins.csv") (built-in parser), @TestData(value="excel:testdata/users.xlsx", sheet="Login") (Apache POI optional dep), @TestData("db:SELECT username, password FROM test_users LIMIT 1") (JDBC via database config); row attribute selects zero-based data row (header excluded); type coercion: integers, doubles, booleans
  • TestClock β€” clock().set("2030-01-01T00:00:00Z") injects a JS Date override into the browser; clock().advance(Duration.ofDays(30)) fast-forwards from current mock; clock().reset() restores real time; auto-reset after every test (no cleanup needed); available via clock() in BaseTest and BaseJUnit5Test

v2.1.0 β€” 2026-05-04

  • BrowserStack integration β€” execution.mode: browserstack + browserstack.username/accessKey/os/osVersion/browser/browserVersion; W3C bstack:options capabilities; mobile device support via device + realMobile; session dashboard URL auto-injected into HTML report as "☁ View Session" link
  • Sauce Labs integration β€” execution.mode: saucelabs + saucelabs.username/accessKey/region/platformName/browser/browserVersion; three regions: us-west-1, eu-central, apac-southeast; W3C sauce:options capabilities; session dashboard URL in HTML report
  • Existing mode: remote (self-hosted Selenium Grid) unchanged β€” all three remote modes coexist

v2.0.0 β€” 2026-05-04

  • Email Verification β€” mailbox().waitForEmail(to("user@example.com")) polls until an email arrives; email.assertSubject(), email.assertBodyContains(), email.extractLink(linkText) for anchor extraction; mailbox().clear() purges the inbox; email.autoClear: true clears automatically before each test
  • Four backends: Mailhog (local/Docker), Mailtrap (hosted sandbox), Outlook/Office 365 (Microsoft Graph API β€” app-only OAuth2, no user login), IMAP (Gmail, Yahoo, any standards-compliant server via optional jakarta.mail dep)
  • Outlook config: tenantId, clientId, clientSecret, mailbox β€” OAuth2 token auto-refreshed and cached

v1.13.0 β€” 2026-05-03

  • @NoBrowser β€” annotate a test class or method to skip WebDriver creation entirely; no Chrome/Firefox window opened, no screenshot/recording/trace; all other framework services (report, steps, metrics, retry, hooks) still active; ideal for database assertions, API-only tests that extend BaseTest, and any test that does not touch the browser

v1.12.0 β€” 2026-05-03

  • Multi-Session Testing β€” withSession("alice", () -> { ... }) runs a lambda with a named browser session active; session("name") returns the raw WebDriver; all named sessions are automatically closed at test end; nested withSession() calls supported via stack-based driver restoration; available in BaseTest and BaseJUnit5Test
  • Database Assertions β€” db().assertRowExists(table, conditions), db().assertNoRow(), db().assertRowCount(), db().query(sql, params).assertValue(column, expected), db().scalar(sql, params); plain JDBC, no ORM dependency; named datasources via db("reporting"); connections pooled per thread and closed automatically at test end
  • New sessions.maxPerTest and database.* config blocks in selenium-boot.yml

v1.11.0 β€” 2026-05-03

  • @Retryable for JUnit 5 β€” InvocationInterceptor in SeleniumBootExtension retries failed test methods with full driver recreation between attempts; @Retryable(maxAttempts = N) on method or class overrides global config
  • @Retryable for Cucumber β€” entire scenario reruns from step 1 with a fresh driver via RetryAnnotationTransformer; retry detected in CucumberHooks and shown as retry badge in HTML report
  • @Retryable β€” new maxAttempts attribute + class-level target; fully backward-compatible

v1.10.0 β€” 2026-05-02

  • JUnit 5 Support β€” SeleniumBootExtension (@ExtendWith) handles driver lifecycle, screenshot on failure, AI analysis, trace, and recording; WebDriver injectable as test method parameter; BaseJUnit5Test base class with getDriver(), getWait(), open(), $(), assertThat(), step(); @EnableSeleniumBoot composed annotation; SeleniumBootLauncherListener generates HTML report when the JUnit Platform test plan finishes (registered via ServiceLoader β€” no config needed); parallel execution via junit-platform.properties

v1.9.0 β€” 2026-05-02

  • BDD / Cucumber Integration β€” BaseCucumberTest runner base + BaseCucumberSteps step definition base (getDriver(), open(), $(), assertThat()); CucumberHooks manages driver lifecycle, metrics, and screenshots per scenario automatically; CucumberStepLogger plugin streams Gherkin step names into the HTML report step timeline; cucumber-java and cucumber-testng declared as optional β€” consumers add their own version; cucumber.properties support for IDE single-scenario runs; Scenario Outlines produce individual report entries per example row

v1.8.0 β€” 2026-04-16

  • Self-Healing Locators β€” locators.selfHealing: true; when waitForVisible/waitForClickable times out, framework automatically tries fallback strategies: extract id from CSS #foo or XPath @id, name from CSS [name] or XPath @name, text from XPath text(), class from CSS .btn, data-testid; healed tests get ⚠ healed badge in HTML report; target/healed-locators.json lists every healed locator after suite
  • AI-Assisted Failure Analysis β€” ai.failureAnalysis: true + ai.apiKey: ${CLAUDE_API_KEY}; on test failure calls claude-haiku-4-5-20251001 with error message, stack trace, step log, URL, and page title; plain-English root-cause + fix suggestion embedded in HTML report below the stack trace; bounded by ai.timeoutSeconds (default 20s); fully non-blocking β€” never affects suite result
  • Flakiness Prediction β€” reads last flakiness.historyRuns (default 20) JSON files from target/metrics-history/; computes per-test failure rate; classifies as STABLE (<10%), WATCH (10–33%), HIGH (β‰₯33%); Flakiness Radar card in HTML report; target/flakiness-report.json; flakiness.failOnHighFlakiness: true to gate builds

v1.7.0 β€” 2026-04-16

  • Trace Viewer β€” tracing.enabled: true generates a self-contained dark-themed target/traces/{Class}/{method}-trace.html per failed test; embeds step timeline with screenshots, final-state screenshot, error message + stack trace; zero CDN dependencies; captureOnPass: true option to trace passing tests too; "View Trace" link appears in the HTML report's failure detail panel

v1.6.0 β€” 2026-04-16

  • Visual regression testing β€” VisualAssert.assertScreenshot() pixel-by-pixel comparison; auto-creates baseline on first run; diff image saved to target/visual-diffs/; configurable tolerance via VisualTolerance.of(n); -DupdateBaselines=true to regenerate
  • Mobile device emulation β€” DeviceEmulator.emulate("iPhone 14") / emulateDevice() in BasePage/BaseTest; CDP-based on Chrome/Edge (viewport, scale factor, UA); window-resize fallback on Firefox; 6 built-in profiles (iPhone 14, iPhone SE, Pixel 7, Galaxy S23, iPad, iPad Pro 12) via DeviceProfiles registry
  • Clipboard helpers β€” ClipboardHelper.write/read/clear() backed by a reliable JS global store
  • GeoLocation mock β€” CDP-based on Chrome/Edge, JS navigator.geolocation override on Firefox
  • Network interception β€” NetworkMock.stub(pattern) stubs API responses via CDP Fetch domain; glob patterns, custom status, delay, auto-cleanup after each test
  • Browser storage helpers β€” StorageHelper.localStorage(), sessionStorage(), cookies() for reading/writing browser storage in tests
  • Fluent Locator API β€” $(css) / $(By) chainable locator: filter(), withText(), within(), nth(), auto-wait terminals
  • Web-First Assertions β€” assertThat(By/Locator) with auto-retry: isVisible, isHidden, hasText, containsText, hasAttribute, hasClass, count

v1.3.0 β€” 2026-04-07

  • Shadow DOM helpers β€” ShadowDom utility + 7 BasePage methods (shadowFind, shadowFindAll, shadowClick, shadowType, shadowGetText, shadowPierce, shadowExists)
  • Alert handling fix β€” unhandledPromptBehavior: ignore on all driver providers; BasePage.getAndAcceptAlert() convenience method
  • Component-aware waits β€” WaitEngine.waitForAngular() (Angular 2+/AngularJS 1.x) and WaitEngine.waitForReactHydration() (React 18/17/16, Next.js)
  • Enhanced HTML report β€” pass rate gauge, donut chart, retry badges, expandable error/stack trace rows, filter bar, search, dark mode, slowest-5 section
  • JUnit XML error details β€” <failure message> now contains the actual assertion message and full stack trace
  • Allure adapter β€” opt-in Allure 2 JSON result files in target/allure-results/ (reporting.allureEnabled: true)
  • Slack / Teams notifications β€” webhook-based post-suite summary with pass/fail counts and failed test list
  • @DependsOnApi β€” skip test immediately (before browser open) if a dependent HTTP endpoint is unreachable; repeatable; cached per suite

v1.1.1 β€” 2026-03-28

  • Schema validation β€” ApiResponse.assertSchema("schemas/user.json") validates response body against a JSON Schema file; requires com.networknt:json-schema-validator:1.4.3 on classpath
  • @UseAuth annotation β€” apply named auth strategy from config to any test method or class
  • ApiAuth.oauth2() β€” OAuth2 client credentials flow with automatic token caching and expiry refresh
  • ApiClient.setGlobalAuth() / clearGlobalAuth() β€” set auth once per suite, applied automatically to all requests

v1.1.0 β€” 2026-03-25

  • BaseApiTest β€” pure API test base class; no browser started; full framework lifecycle (reporting, @TestData, retry, CI gates)
  • ApiClient β€” fluent HTTP client backed by Java's built-in HttpClient; GET, POST, PUT, PATCH, DELETE; auto step-logging
  • ApiResponse β€” rich response wrapper; JSONPath extraction ($.user.id), asObject(Class), fluent assertions (assertStatus, assertJson, assertBodyContains)
  • ApiAuth β€” bearerToken(token), basicAuth(user, pass) auth strategies
  • ScenarioContext β€” thread-local in-test store; ctx().set/get; auto-cleared after each test
  • SuiteContext β€” global thread-safe store for cross-test state; suiteCtx().set/get
  • apiClient(), ctx(), suiteCtx() added to BaseTest for hybrid UI+API tests

v0.10.0 β€” 2026-03-22

  • @TestData β€” annotation-driven test data injection; loads JSON/YAML from src/test/resources/testdata/; env-specific override (admin.staging.json overrides admin.json when -Denv=staging); getTestData() in BaseTest
  • Browser matrix β€” browser.matrix: [chrome, firefox] in YAML runs every test on every browser in one mvn test; Browser column in HTML report; per-browser JUnit XML for Jenkins matrix view
  • SessionCache β€” SessionCache.store("name") / SessionCache.restore("name"); global cross-thread session reuse; reduces repeated login overhead in large parallel suites
  • SoftAssert β€” softAssert().that(condition, "message") collects failures without throwing; framework flushes at test end; single screenshot captured; all failures appear as individual step entries in the report

v0.9.6 β€” 2026-03-21

  • DownloadManager browser auto-configuration β€” Chrome and Firefox automatically configure download directory from browser.downloadDir config; no save dialog shown; partial downloads (.crdownload, .part) filtered out
  • Remote mode guard β€” download prefs skipped when execution.mode: remote (Grid sessions download to node filesystem, not local)
  • File upload helper β€” BasePage.upload(By, String) resolves paths via absolute β†’ classpath β†’ project-root; CI-safe

v0.9.5 β€” 2026-03-21

  • ConsoleErrorCollector auto-integration β€” when browser.captureConsoleErrors: true, the JS shim is auto-injected on every open() call and errors are auto-collected at test end as WARN step entries in the report
  • failOnConsoleErrors enforcement β€” when browser.failOnConsoleErrors: true, a passing test with JS errors is marked FAILED with a clear error listing the detected errors
  • StepStatus.WARN β€” new step status for JS error entries (does not affect test outcome)

v0.9.4 β€” 2026-03-20

  • iFrame helpers expanded β€” withinFrameName(String, Runnable) added; withinFrame, withinFrameIndex, withinFrameName now support nested frames (inner calls restore to parentFrame(), outermost restores to defaultContent())

v0.9.3 β€” 2026-03-20

  • Bug fix β€” alert methods (acceptAlert, dismissAlert, getAlertText, typeInAlert) in BasePage now use this.driver directly instead of WaitEngine/DriverManager, matching the driver reference used by the page object
  • Bug fix β€” @PreCondition failure error message now shows the real exception instead of "null" (unwraps InvocationTargetException)

v0.9.2 β€” 2026-03-20

  • Bug fix β€” precondition failure now throws SkipException (not RuntimeException); prevents retry from firing and a second browser from opening on @PreCondition setup failures
  • Bug fix β€” maxAttempts: 0 in YAML now respected; changed int field default to nullable Integer so intentional 0 is never silently overridden by programmatic defaults

v0.9.1 β€” 2026-03-19

  • Alert wait fix β€” acceptAlert, dismissAlert, getAlertText, typeInAlert now use WaitEngine.waitForAlert() β€” no more NoAlertPresentException on slow pages
  • WaitEngine.waitForAlert() β€” new explicit wait for browser alert presence
  • BasePage.smartFind() β€” convenience wrapper; use inside page objects without passing the driver

v0.9.0 β€” 2026-03-18

  • BasePage expanded β€” dropdowns (selectByText, selectByValue, selectByIndex, getSelectedOption), alerts (acceptAlert, dismissAlert, getAlertText, typeInAlert), mouse actions (hover, doubleClick, rightClick), scroll (scrollTo, scrollToTop, scrollToBottom), JS fallbacks (jsClick, jsType)

v0.8.0 β€” 2026-03-17

  • BasePage β€” page object base class: click, type, getText, isDisplayed, withinFrame, withinFrameIndex, upload
  • SmartLocator β€” tries multiple By strategies in order, returns first visible element
  • DownloadManager β€” waitForFile, waitForAnyFile, clearDownloads with partial-download detection
  • ConsoleErrorCollector β€” JS console error capture (Chrome via WebDriver logs, Firefox via injected shim)
  • @PreCondition β€” session-aware pre-conditions with cookie + localStorage caching per thread
  • @ConditionProvider + BaseConditions β€” define named condition providers, registered via SPI
  • @SeleniumBootApi β€” annotation marking stable public API with since version
  • FrameworkVersion + minFrameworkVersion() β€” runtime version checks, plugin compatibility enforcement
  • Config additions β€” browser.downloadDir, browser.captureConsoleErrors, browser.failOnConsoleErrors

v0.7.0 β€” 2026-03-16

  • StepLogger β€” named test steps with timestamps and optional per-step screenshots
  • Step timeline β€” step-by-step execution timeline in the HTML report Failures tab
  • Tabbed HTML report β€” Dashboard, Test Cases, and Failures tabs with collapsible rows
  • Browser lifecycle β€” browser.lifecycle: per-test | per-suite configuration

v0.6.0 β€” 2025-12-01

  • Advanced HTML report β€” pass rate gauge, donut chart, slowest tests card, retry badges
  • Self-contained report β€” screenshots base64-encoded, single file, no external dependencies

v0.5.0 β€” 2025-10-15

  • Retry support β€” retry.enabled + retry.maxAttempts in selenium-boot.yml
  • @Retryable β€” per-method retry override
  • Retry metrics β€” retry counts tracked in ExecutionMetrics and exported to JSON

v0.4.0 β€” 2025-08-20

  • CI auto-detection β€” GitHub Actions, Jenkins, CircleCI, GitLab CI; forces headless, tunes thread count
  • Container detection β€” Docker and Kubernetes; auto-applies Chrome container flags
  • JUnit XML reporter β€” target/surefire-reports/TEST-SeleniumBoot.xml
  • Build quality gates β€” BuildThresholdEnforcer enforces pass-rate and flaky-test thresholds
  • CI templates β€” GitHub Actions workflow and Jenkinsfile included

v0.3.0 β€” 2025-06-10

  • Plugin system β€” SeleniumBootPlugin + PluginRegistry with SPI discovery
  • Custom driver providers β€” NamedDriverProvider + DriverProviderRegistry
  • Custom report adapters β€” ReportAdapter + ReportAdapterRegistry
  • Lifecycle hooks β€” ExecutionHook + HookRegistry
  • SeleniumBootDefaults β€” programmatic config defaults for shared test-base JARs

v0.2.0 β€” 2025-04-05

  • WaitEngine β€” fluent explicit wait API
  • Thread-safe config β€” SeleniumBootContext with AtomicReference
  • Session semaphore β€” maxActiveSessions cap with fair wait
  • Global retry β€” retry.enabled: true retries all tests without @Retryable

v0.1.0 β€” 2025-02-01

  • Initial release β€” Chrome/Firefox, TestNG integration, selenium-boot.yml, basic HTML report, screenshot on failure

Sample Project

A working demo project covering all framework features is available at: github.com/seleniumboot/selenium-boot-test


Documentation

Full documentation at seleniumboot.github.io/selenium-boot


License

Licensed under the Apache License, Version 2.0.


Contributing

See CONTRIBUTING.md.


Disclaimer

Selenium Boot is an independent open-source project and is not affiliated with Selenium or the Spring Framework.