Skip to content

seleniumboot/selenium-boot

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 testingBaseApiTest for pure API tests; fluent ApiClient with auth, schema validation, JSONPath; hybrid UI + API tests in the same suite
  • 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>2.4.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

v2.4.0 — 2026-05-19

  • Performance AssertionsassertPerformance().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 Quarantineselenium-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
  • TestClockclock().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 integrationexecution.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 integrationexecution.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 Verificationmailbox().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 TestingwithSession("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 Assertionsdb().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 5InvocationInterceptor 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 SupportSeleniumBootExtension (@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 IntegrationBaseCucumberTest 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 Locatorslocators.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 Analysisai.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 Viewertracing.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 testingVisualAssert.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 emulationDeviceEmulator.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 helpersClipboardHelper.write/read/clear() backed by a reliable JS global store
  • GeoLocation mock — CDP-based on Chrome/Edge, JS navigator.geolocation override on Firefox
  • Network interceptionNetworkMock.stub(pattern) stubs API responses via CDP Fetch domain; glob patterns, custom status, delay, auto-cleanup after each test
  • Browser storage helpersStorageHelper.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 AssertionsassertThat(By/Locator) with auto-retry: isVisible, isHidden, hasText, containsText, hasAttribute, hasClass, count

v1.3.0 — 2026-04-07

  • Shadow DOM helpersShadowDom utility + 7 BasePage methods (shadowFind, shadowFindAll, shadowClick, shadowType, shadowGetText, shadowPierce, shadowExists)
  • Alert handling fixunhandledPromptBehavior: ignore on all driver providers; BasePage.getAndAcceptAlert() convenience method
  • Component-aware waitsWaitEngine.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 validationApiResponse.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)
  • ApiAuthbearerToken(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 matrixbrowser.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
  • SessionCacheSessionCache.store("name") / SessionCache.restore("name"); global cross-thread session reuse; reduces repeated login overhead in large parallel suites
  • SoftAssertsoftAssert().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 helperBasePage.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 expandedwithinFrameName(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 fixmaxAttempts: 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 fixacceptAlert, 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
  • DownloadManagerwaitForFile, 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 additionsbrowser.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 lifecyclebrowser.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 supportretry.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 reportertarget/surefire-reports/TEST-SeleniumBoot.xml
  • Build quality gatesBuildThresholdEnforcer enforces pass-rate and flaky-test thresholds
  • CI templates — GitHub Actions workflow and Jenkinsfile included

v0.3.0 — 2025-06-10

  • Plugin systemSeleniumBootPlugin + PluginRegistry with SPI discovery
  • Custom driver providersNamedDriverProvider + DriverProviderRegistry
  • Custom report adaptersReportAdapter + ReportAdapterRegistry
  • Lifecycle hooksExecutionHook + HookRegistry
  • SeleniumBootDefaults — programmatic config defaults for shared test-base JARs

v0.2.0 — 2025-04-05

  • WaitEngine — fluent explicit wait API
  • Thread-safe configSeleniumBootContext with AtomicReference
  • Session semaphoremaxActiveSessions cap with fair wait
  • Global retryretry.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.