Skip to main content

Changelog

All notable changes to Selenium Boot are documented here.

[Unreleased]​

  • Failed tests with trace links in GitHub Actions job summary — when running inside GitHub Actions and tracing.enabled: true is on, failed tests are automatically summarized in a Markdown table (test name, error message, and path to the HTML trace file) appended to $GITHUB_STEP_SUMMARY. Triage failures and locate trace paths directly from the Actions job summary without downloading artifact bundles; no-op outside Actions or when all tests pass. (#137)

  • Bounded failure detail record — every failed test now exports one optional-field failureDetail object with the failing locator, top application frame, last successful step, page URL/title, heal events, console errors, retry/history status, and representative same-cause context. The HTML failure panel and opt-in AI prompt reuse this record; raw errors and stack traces remain available. Text/list/URL limits and the exact AI data disclosure are documented. (#142)

  • Locator: waitFor(State), allTextContents(), and element screenshot() — waitFor(State) (and waitFor()) waits for an element to reach a target lifecycle state (VISIBLE, HIDDEN, ATTACHED, DETACHED), retrying up to timeouts.explicit. allTextContents() returns the text content of all matched elements in a single pass without waiting if empty, re-resolving if an element goes stale during read. screenshot() returns the element's PNG bytes, and screenshot(Path) writes them to a file path; both terminal actions re-resolve on every poll to survive stale elements. (#135)

  • flakiness.historyDir / -Dseleniumboot.history.dir — metrics history can now live outside target/. Builds that clean target/ or discard the CI workspace between runs had no history, so the Flakiness Radar and the newly/consistently-failing and intermittent statuses stayed empty. Point it at a directory your CI restores and saves (a cache or artifact store); the system property wins over the config. Default unchanged: <reports dir>/metrics-history. (#141)

  • Retry- and history-aware test status — each test now gets a status from this run's retries and the earlier runs in target/metrics-history/: Passed on retry, Newly failing (passed in every earlier run in the window), Consistently failing (failed in the two or more earlier runs) or Intermittent (mixed earlier results). A "Test status" card sits next to the Flakiness Radar, the status shows in the failure detail, and newly failing tests are listed first in the Failures tab. The metrics JSON gains testStatus. Radar thresholds and failOnHighFlakiness are unchanged. (#141)

  • Failure grouping — the report's Failures tab now opens with a "N tests, same cause" panel: failed tests are grouped by a signature of category, exception type, normalised message (ids, numbers and quoted values stripped) and top application stack frame. The flat per-class list is unchanged below it. With ai.failureAnalysis on, one Claude call is made per group; the other tests in the group reuse its analysis. The metrics JSON gains failureSignature. (#140)

  • Locator form actions: clear(), check(), uncheck(), isChecked(), selectOption(text), selectOptionByValue(value), inputValue() — form controls can now be manipulated and inspected directly on Locator without falling back to BasePage helpers or raw WebElements. check() and uncheck() are idempotent (no click if already in the target state), isChecked() queries checked state without waiting, and terminal actions (clear, check, uncheck, selectOption, selectOptionByValue, inputValue) auto-wait, re-resolving from scratch on every poll to survive stale or late-appearing elements. (#133)


[Unreleased]​

  • Failure classification — every failed test is tagged with a category (LOCATOR_NOT_FOUND, ELEMENT_NOT_INTERACTABLE, STALE_ELEMENT, TIMEOUT, ASSERTION_MISMATCH, NAVIGATION_ERROR, BROWSER_CRASH, or UNKNOWN) and the evidence for it, from the exception class chain and message alone. No AI, no API key, no network. Shown as a badge in the HTML report's failure panel, as failureCategory / failureEvidence in the metrics JSON, and as the type of <failure> in the JUnit XML. The raw error and stack trace are unchanged. (#139)

[3.8.0] — 2026-10-11​

  • Locator.first() and Locator.last() — narrow matches to the first or last matching element (e.g. getByRole(Role.LISTITEM).first()). Both resolve at action time, re-evaluating candidate elements on every poll and retrying stale/not-yet-present elements up to timeouts.explicit. (#132)

  • HTML report: the "Avg Time (ms)" stat tile is now "Suite Time" — the wall-clock suite duration in hh:mm:ss, matching the sidebar.

  • HTML report: suite duration in hh:mm:ss, wall-clock. The report previously showed the sum of every test's time in milliseconds, which overstates a parallel run. It now shows how long the suite actually ran (01:42:07; hours aren't capped). The metrics JSON gains suiteDurationMs; totalTimeMs (summed test time) is unchanged.

  • HTML report: results first. The dashboard now opens with a one-line run summary and the stat cards; the full run configuration moved into a collapsed "Run configuration" block at the bottom, with empty rows (Grid URL, unset CI fields) dropped. A "View failures" shortcut appears when any test failed.


[3.7.0] — 2026-10-04​

  • Locator.dragTo(Locator) — drags one element onto another, including HTML5 drag-and-drop pages that ignore the native gesture. See Drag and drop. (#101)
  • debug.slowMoMs / debug.highlight — dev-only live-triage aids: pause after each Locator action and outline the element about to be acted on. Off by default, no cost when off; not for CI. See Debug. (#52)
  • withNewWindow(opener, body) / withNewTab(...) on BasePage — run the click that opens a new window, switch to it, run your checks, close it and return to the original window, even if the checks throw. No window opening within timeouts.explicit throws TimeoutException. See Handle new windows and tabs. (#49)
  • browser.version — optional exact browser version for local Chrome/Firefox runs, resolved by Selenium Manager. Omit it to use the installed browser. (#51)

[3.6.0] — 2026-09-27​

  • WaitEngine.waitForNetworkIdle() / waitForResponse(urlPattern) — waits until no network request has been in flight for a quiet period (default 500ms, or a custom Duration), or until a response whose URL matches a glob pattern (same syntax as NetworkMock.stub) is observed, returning its HTTP status code. Both are bounded by the configured explicit timeout. Works on Chrome/Edge (via CDP) and any BiDi-capable browser such as Firefox; throws UnsupportedOperationException on others. Firefox sessions now request a BiDi connection by default (webSocketUrl capability) so this works with no extra configuration — an explicit value in the user's own browser.capabilities still wins.
  • open() names execution.baseUrl when the site can't be reached — a DNS or connection failure now reads Could not reach <url> (ERR_NAME_NOT_RESOLVED) — check execution.baseUrl in selenium-boot.yml … (the driver's error stays as the cause) instead of a bare net::ERR_NAME_NOT_RESOLVED. Applies to BaseTest, BaseJUnit5Test, BaseCucumberSteps and BaseConditions. Also fixes BaseJUnit5Test.open() with no execution.baseUrl failing with a bare driver error instead of naming the missing key. (#84)
  • Gradle projects now get their reports under build/ (#81) — the base directory is decided from build.gradle / build.gradle.kts (a pom.xml wins if both exist) instead of "does target/ exist", which other components had already created. Flakiness report, healed locators, traces, recordings, Allure results, screenshots and JUnit XML all follow it; -Dseleniumboot.reports.dir still overrides.
  • Docs: the Gradle systemProperties System.properties snippet is replaced (#82) — copying every JVM property broke test runs when the test JVM differs from Gradle's. It now forwards only browser and env.

[3.5.0] — 2026-09-24​

  • Zero-config first run: selenium-boot.yml is now optional — with no default selenium-boot.yml in the working directory or on the classpath, the framework runs on built-in defaults (browser.name: chrome, execution.mode: local, timeouts.explicit: 10, timeouts.pageLoad: 30) and prints one [Selenium Boot] No selenium-boot.yml found — running with built-in defaults ... notice line. Fields a file omits (and an empty file) fall back to the same defaults; browser.name is only defaulted when browser.matrix is not set, and SeleniumBootDefaults overrides still take precedence over the built-ins. Nothing that was an error before stops being one: a requested profile (-Dselenium.boot.profile) or explicit path (-Dselenium.boot.config) whose file is missing still throws, so a typo never silently runs on defaults, and present-but-invalid values (an unknown execution.mode, a negative timeout) still fail validation. Adds ConfigurationLoader.load(File, ClassLoader) (working directory and classpath supplied, for tests). (#66)
  • Terminal Locator actions wait for the element and re-resolve it on every poll — click(), type(), append(), getText(), getAttribute(), hover(), scrollIntoView(), jsClick() and element() used to look the element up once and act on that cached reference, so a page that re-rendered it in between surfaced as a StaleElementReferenceException, and a locator that matched nothing yet threw immediately. They now resolve the locator from scratch on each poll, retrying on a stale or not-yet-present element until timeouts.explicit elapses. Behavior change: a locator that matches nothing is now retried for up to timeouts.explicit instead of failing at once. If it never matches, the call still ends in a LocatorException (cause: TimeoutException), so existing catches keep working; an element that exists but never becomes visible/clickable still times out with a TimeoutException, as before. isVisible(), isHidden(), isEnabled() and count() still never wait, and rows() inherits the wait for its table through element(). (#67, #68)
  • JUnit Jupiter API bumped 5.10.2 → 6.1.3 (junit-jupiter-api, optional dependency of the JUnit 5 bridge). junit-platform-launcher is now bumped to match (6.1.3, was 1.10.2), closing the pairing gap left by #64. Verified both directions against the consumer integration suite (11/11 real-browser JUnit 5 tests): a consumer still on JUnit 5.10.2 + launcher 1.10.2 keeps working unchanged, and a consumer on JUnit 6 (jupiter 6.1.3 + launcher 6.1.3) now works too. (#64)
  • Clearer error when execution.baseUrl is unset — open() and open(String) now throw execution.baseUrl is not set — add it to selenium-boot.yml, or navigate with getDriver().get(url) instead of baseURL is null or empty. Message only; still an IllegalStateException. The getting-started guide now says Step 3 needs the Step 2 file, since zero-config has no default baseUrl. (#77)

[3.4.0] — 2026-09-19​

Added​

  • Locator.rows() — resolves a locator to a <table> and returns its data rows as header-keyed maps (List<Map<String, String>>), one map per row, keyed by column header. Headers come from the first <thead> row with <th> cells, falling back to the first <tr> anywhere with <th> cells, then the first <tr>'s <td> cells; whichever row supplies headers is never returned as data. Short rows are padded with "", extra cells are dropped, and <th>-only rows (group headings) are skipped. Contributed by @timothytkim. (#54)

Fixed​

  • Bootstrap failures now expose their root cause — when framework initialization throws, the full cause chain is now logged to System.err (walked down to the root) before the suite aborts, so the actual failure reason shows up in normal Maven/TestNG/Surefire output instead of being hidden behind the generic "failed to initialize" wrapper message. (Fixes #45)

Changed​

  • Selenium Java 4.40.0 → 4.49.0 (9 releases) — behavior-preserving upgrade. NetworkMock and DeviceEmulator are repointed from the removed CDP devtools.v144 module to devtools.v153, and two new trailing Optional.empty() arguments were added to Emulation.setDeviceMetricsOverride() calls to match v153's changed signature, preserving existing defaults. Verified with the full 508-test suite.
  • Docs — quickstart examples in the README and getting-started guide now lead with the locator API ($(...)) instead of getDriver(), and the getting-started example runs as written.

[3.3.0] — 2026-08-15​

Fixed​

  • execution.parallel validation now matches TestNG's own parallel modes — tests and instances are legitimate TestNG modes that flow straight through to XmlSuite.setParallel() and behave exactly like methods/classes downstream, but Selenium Boot's bootstrap validator rejected both, reporting a misleading "Parallel execution configuration missing" for a value that was present but not on a hand-written allowlist. Validation now delegates to TestNG's XmlSuite.ParallelMode enum directly, so none, methods, classes, tests, and instances are all accepted, and an unrecognised value's error message names both the rejected value and the full valid set. (Fixes #35)

[3.2.0] — 2026-07-18​

Added​

  • Three new WaitEngine conditions, consistent with the existing waitFor* naming:
    • waitForAttribute(By, attribute, value) — waits for an exact attribute match (see waitForAttributeContains for a substring match).
    • waitForUrlMatches(String regex) — waits for the current URL to match a regular expression (see waitForUrlContains for a substring match).
    • waitForTextMatches(By, String regex) — waits for an element's visible text to match a regular expression.
    • Purely additive to the @SeleniumBootApi surface — no breaking changes.

[3.1.1] — 2026-06-26​

Fixed​

  • Report overwrite with multiple test engines — the metrics JSON, HTML report, and metrics history now honor the seleniumboot.reports.dir system property (default target). When a TestNG suite (Surefire) and JUnit 5 tests (Failsafe) run in the same build, point each engine's run at its own directory (e.g. -Dseleniumboot.reports.dir=target/junit5) so they no longer overwrite each other's HTML report. New ReportPaths helper centralizes path resolution.

[3.1.0] — 2026-06-25​

Added​

  • Accessibility-first locators — Playwright-style semantic locators available on BaseTest and BasePage: getByRole, getByText, getByLabel, getByPlaceholder, getByTestId, getByAltText, getByTitle. They target the accessibility tree the user perceives rather than brittle CSS/DOM structure, so tests survive redesigns.
  • getByRole(Role) — 38 WAI-ARIA roles, each matching implicit HTML elements (<button>, <a href>, <h1>…) and explicit role="…" attributes. Refine with .withName("Submit") (accessible-name match, following ARIA precedence: aria-label → aria-labelledby → associated <label> → text → value/alt/title) and .withLevel(1) (heading level).
  • Case-insensitive substring matching by default, with .exact() opt-in. All locators flow through the existing auto-wait Locator chain — no Thread.sleep, no explicit waits.
  • toBy() escape hatch — every semantic locator can return its synthesized Selenium By for interop with raw Selenium or SmartLocator.
  • Configurable test-id attribute — locators.testIdAttribute in selenium-boot.yml (default data-testid).

[3.0.0] — 2026-06-21​

Added​

  • TestRail Integration — @TestRailCase("C1234") on any test method (or class) pushes results to TestRail automatically; supports multiple IDs (@TestRailCase({"C1234", "C5678"})); creates a named run on suite start (autoCreateRun: true); maps PASSED→1, FAILED→5, SKIPPED→Retest(4); failure exception message is sent as the result comment
  • Xray Integration — @XrayTest("PROJ-123") pushes results to Xray Cloud or Xray Server/DC; Cloud uses OAuth2 client credentials; Server uses HTTP Basic auth against Jira; results are batch-imported at suite end
  • Zero extra dependencies — both clients use java.net.http.HttpClient (built into Java 17)
  • TestNG + JUnit 5 — same annotations work in both test frameworks; framework automatically detects and routes to the correct listener

Config​

testmanagement:
testrail:
enabled: true
url: https://yourcompany.testrail.io
username: user@example.com
apiKey: YOUR_API_KEY
projectId: 1
suiteId: 2 # optional — omit for single-suite projects
runName: "Selenium Boot – CI run"
autoCreateRun: true # set false and provide runId to use an existing run

xray:
enabled: true
mode: cloud # "cloud" (Jira Cloud) or "server" (Server / Data Center)
# Cloud fields:
clientId: YOUR_CLIENT_ID
clientSecret: YOUR_CLIENT_SECRET
# Server/DC fields:
# jiraUrl: https://jira.example.com
# username: admin
# password: secret
projectKey: PROJ
testPlanKey: PROJ-1 # optional — links the execution to a Test Plan

[2.6.0] — 2026-06-20​

Added​

  • Gradle Build Support — testImplementation 'io.github.seleniumboot:selenium-boot:2.6.0' + test { useTestNG() } is the complete Gradle setup; full docs cover Groovy DSL, Kotlin DSL, JUnit 5 bridge, parallel execution, optional dependencies, and ./gradlew test equivalents for all mvn commands
  • JUnit XML auto-detection — JUnitXmlReporter now detects the active build tool at runtime: writes to build/test-results/test/ (Gradle) when only a build/ directory exists, or target/surefire-reports/ (Maven) otherwise; override with -Dseleniumboot.reports.dir= system property
  • Cross-build-tool version reporting — FrameworkVersion.get() now reads Implementation-Version from the JAR's MANIFEST.MF as the primary source (works with both Maven and Gradle); falls back to META-INF/maven/.../pom.properties (Maven-only) and then "0.0.0"; maven-jar-plugin configured with addDefaultImplementationEntries: true to populate the manifest on every Maven build

[2.5.0] — 2026-06-20​

Added​

  • Accessibility Assertions (axe-core) — accessibility() in BaseTest and BaseJUnit5Test runs a full axe-core WCAG scan on the active page; axe-core 4.10.2 bundled in the JAR — no CDN, no extra Maven dependency required
  • Fluent builder: .withTags("wcag2a", "wcag21aa") restricts rules to WCAG 2.1 AA; .withLevel(Impact.SERIOUS) filters violations by minimum severity; .excluding("#cookie-banner") skips known third-party elements; .withContext("#main-form") scopes the scan to a subtree
  • .run() — asserts zero violations and throws a detailed AssertionError on failure, showing rule ID, severity (CRITICAL/SERIOUS/MODERATE/MINOR), fix guidance, element CSS selector path, and link to the axe-core docs for each failing node
  • .collect() — returns raw AccessibilityResult for custom inspection without asserting; result.violations(), result.violationsAtLevel(Impact.SERIOUS), result.passCount()
  • Impact enum with ordering: CRITICAL > SERIOUS > MODERATE > MINOR; Impact.fromString(str) parses axe-core impact strings
  • AccessibilityResult, AccessibilityViolation, AccessibilityViolation.NodeDetail all available via accessibility().collect() for custom reporting or soft assertions

[2.4.0] — 2026-05-19​

Added​

  • Performance Assertions (Core Web Vitals) — assertPerformance() collects LCP, FCP, TTFB, CLS, DOM load, and page load from the active browser page using browser-native APIs (window.performance.getEntriesByType()); no extra dependency or proxy required
  • Fluent assertion chain: .lcp().isBelow(2500).fcp().isBelow(1800).ttfb().isBelow(600).cls().isBelow(0.1) with colour-coded error messages showing actual vs threshold values
  • collectPerformance() — raw PerformanceMetrics access for custom assertions or logging
  • LCP/CLS available on Chrome/Edge only; assertions on unavailable metrics are silently skipped (not failed), enabling cross-browser test suites
  • performance.captureOnEveryTest: true — auto-captures metrics after every passing test; ⚡ Performance strip with green/yellow/red chips shown in the HTML report test detail panel
  • PerformanceAssert, PerformanceMetrics, PerformanceCollector all available via clock() pattern in BaseTest and BaseJUnit5Test

Config​

performance:
captureOnEveryTest: false # show metrics in HTML report for every test
lcpWarnMs: 2500
fcpWarnMs: 1800
ttfbWarnMs: 800
clsWarn: 0.1

[2.3.0] — 2026-05-17​

Added​

  • Test Quarantine — selenium-quarantine.yml in the project root lists tests to skip permanently; committed to version control so it survives fresh CI clones; supports TestNG, JUnit 5, and Cucumber; two entry formats: plain string (com.example.LoginTest#method) and structured with optional reason (test: …\nreason: "JIRA-123")
  • Class-level quarantine — a class-only entry (com.example.PaymentTest) skips every method in that class
  • Cucumber quarantine — two methods: (1) add @quarantine tag to a scenario in the .feature file; (2) list entries in selenium-quarantine.yml using any of three formats: by Cucumber tag ("@smoke" — bulk across all features carrying that tag), by feature file (login.feature — all scenarios in the file), or by feature+name ("login.feature#Login with expired session" — specific scenario without editing the feature file)
  • quarantine.enabled flag — set to false to temporarily run the full suite without removing entries from the file
  • File resolution — system property -Dselenium.boot.quarantine=, working directory, classpath (in that order); missing file = silent no-op

Config​

quarantine:
enabled: true # false = disable without editing the file
cucumberTag: quarantine # Cucumber tag name (without @)
selenium-quarantine.yml
quarantine:
- com.example.tests.LoginTest#loginWithExpiredSession
- com.example.tests.PaymentTest # entire class
- test: com.example.tests.SearchTest#searchSpecial
reason: "JIRA-1234 — Unicode handling broken"

[2.2.0] — 2026-05-12​

Added​

  • External @TestData sources — @TestData now accepts csv:, excel:, and db: prefixes in addition to the existing JSON/YAML files; sheet attribute selects an Excel worksheet; row attribute picks the zero-based data row (header excluded); type coercion applied automatically (integers, doubles, booleans); Apache POI required for Excel (add poi-ooxml:5.2.5 to your project, optional dep)
  • CSV source — @TestData("csv:testdata/logins.csv") — RFC 4180 quoting support, built-in parser, no extra dependency
  • Excel source — @TestData(value = "excel:testdata/users.xlsx", sheet = "Login") — reads XLSX via Apache POI; cell type mapping (numeric → long/double, date-formatted → ISO string, boolean → Boolean)
  • DB source — @TestData("db:SELECT username, password FROM test_users WHERE active=1") — executes against the database config block; first result row loaded; participates in per-test connection lifecycle
  • TestClock — clock().set("2030-01-01T00:00:00Z") injects a JS Date override into the browser; clock().advance(Duration.ofDays(30)) fast-forwards relative to the current mock; clock().reset() restores real time; all three available via clock() in BaseTest and BaseJUnit5Test; auto-reset called automatically after every test (pass, fail, skip)
  • clock config block: clock.injectHeader / clock.headerName for optional server-side date header propagation

Config​

clock:
injectHeader: false # send X-Mock-Date header to server
headerName: X-Mock-Date

[2.1.0] — 2026-05-04​

Added​

  • BrowserStack integration — execution.mode: browserstack; BrowserStackProvider builds W3C bstack:options capabilities from YAML config; supports desktop (os, osVersion, browser, browserVersion) and mobile (device, realMobile); raw bstack:options overrides via capabilities map; zero test-code change — all framework features work identically
  • Sauce Labs integration — execution.mode: saucelabs; SauceLabsProvider builds W3C sauce:options capabilities; three regions supported: us-west-1, eu-central, apac-southeast; raw sauce:options overrides via capabilities map
  • Cloud session URL in HTML report — after driver creation on BrowserStack or Sauce Labs, the session dashboard URL is captured from the remote session ID and stored; HTML report shows a "☁ View Session" link in the test detail panel linking directly to the BrowserStack/Sauce video and logs
  • DriverManager.getCloudSessionUrl() — public accessor for the current thread's cloud session URL; null when running locally or against a self-hosted grid

Config​

execution:
mode: browserstack # or: saucelabs | remote | local

browserstack:
username: ${BS_USER}
accessKey: ${BS_KEY}
os: Windows
osVersion: "11"
browser: chrome
browserVersion: latest

saucelabs:
username: ${SAUCE_USER}
accessKey: ${SAUCE_KEY}
region: us-west-1 # us-west-1 | eu-central | apac-southeast
platformName: "Windows 11"
browser: chrome
browserVersion: latest

[2.0.0] — 2026-05-04​

Added​

  • Email Verification — mailbox().waitForEmail(criteria) polls the inbox until a matching email arrives or the configured timeout expires; fluent criteria: to(address), .subject(text), .containing(text), .timeout(seconds); Email value object with assertSubject(), assertBodyContains(), extractLink(linkText) (finds href of anchor by visible text); mailbox().clear() purges the inbox; email.autoClear: true clears automatically before each test; to(address) shorthand available directly in BaseTest / BaseJUnit5Test (no static import needed)
  • Mailhog provider — polls GET /api/v2/messages, parses multipart MIME; DELETE /api/v1/messages to clear; ideal for local dev and CI Docker
  • Mailtrap provider — Mailtrap v1 REST API; Api-Token header auth; PATCH /clean to clear
  • Outlook / Office 365 provider — Microsoft Graph API with app-only OAuth2 client credentials (no user sign-in); token auto-refreshed and cached; reads GET /users/{mailbox}/messages; deletes per-message; setup: register Azure AD app, grant Mail.Read + Mail.ReadWrite application permissions, admin consent
  • IMAP provider — connects to any IMAP server (Gmail app passwords, Yahoo, corporate); SSL/STARTTLS configurable; requires optional com.sun.mail:jakarta.mail:2.0.1 consumer dependency; helpful error thrown if jar missing

Changed​

  • BaseTest / BaseJUnit5Test — new mailbox() and to(address) protected methods
  • SeleniumBootConfig — new email block with provider, timeoutSeconds, pollIntervalMs, autoClear, mailhog, mailtrap, outlook, imap sub-sections

[1.13.0] — 2026-05-03​

Added​

  • @NoBrowser — class- or method-level annotation that tells the framework to skip all browser operations for that test: no WebDriver created, no recording started, no screenshot captured, no trace saved, no driver quit; all other services (HTML report, step timeline, ExecutionMetrics, retry, CI gates, hooks, @TestData, ScenarioContext) continue to work; available in BaseTest (TestNG) and BaseJUnit5Test (JUnit 5); designed for database assertions, file checks, or any non-UI logic in tests that extend BaseTest rather than BaseApiTest

[1.12.0] — 2026-05-03​

Added​

  • Multi-Session Testing — withSession("alice", () -> { ... }) switches the active driver to a named session for the duration of the lambda and restores the previous driver on exit; session("name") returns the named WebDriver directly; all named sessions are automatically closed at test end; nested withSession() calls supported via a stack-based override in DriverManager; available in BaseTest (TestNG), BaseJUnit5Test (JUnit 5), and through MultiSessionManager directly
  • Database Assertions — JDBC-backed DbClient with assertRowExists(table, conditions), assertNoRow(table, conditions), assertRowCount(table, expected), assertRowCount(table, where, expected), query(sql, params).assertValue(column, expected), query(sql, params).value(column), and scalar(sql, params); plain java.sql.DriverManager — no ORM or extra dependency; named datasources via db("reporting"); connections cached per thread and closed automatically at test end; DbAssertException extends AssertionError so failures appear as test failures
  • sessions.maxPerTest and database config blocks added to SeleniumBootConfig

[1.11.0] — 2026-05-03​

Added​

  • @Retryable for JUnit 5 — SeleniumBootExtension implements InvocationInterceptor; interceptTestMethod catches failures and retries the test method with full driver recreation between attempts; @Retryable can be placed on the method or the class; maxAttempts attribute overrides the global retry.maxAttempts config; WebDriver parameter arguments are re-resolved to the new driver on each retry attempt
  • @Retryable for Cucumber — RetryAnnotationTransformer applies TestNG retry to AbstractTestNGCucumberTests.runScenario; the entire scenario reruns from step 1 with a fresh driver per retry; CucumberHooks.beforeScenario detects retries (testId already in metrics) and records retry count so the HTML report shows the retry badge

Changed​

  • @Retryable — added maxAttempts attribute (default -1 = use config); added TYPE target so it can be placed on a class to retry all its test methods; fully backward-compatible — existing usages without the attribute continue to work

[1.10.0] — 2026-05-02​

Added​

  • JUnit 5 Support — SeleniumBootExtension (@ExtendWith) provides full lifecycle: driver creation in beforeEach, screenshot + error recording + AI analysis + trace + recording in afterEach (via context.getExecutionException()), per-suite driver cleanup in afterAll; WebDriver injectable as a test method parameter via ParameterResolver; BaseJUnit5Test base class with getDriver(), getWait(), open(), $(), assertThat(), step(); @EnableSeleniumBoot composed annotation; SeleniumBootLauncherListener (TestExecutionListener) generates HTML report, JSON metrics, and flakiness analysis when the JUnit Platform test plan finishes — registered automatically via META-INF/services; junit-platform-launcher declared as optional dependency; parallel execution supported via junit-platform.properties

[1.9.0] — 2026-05-02​

Added​

  • BDD / Cucumber Integration — BaseCucumberTest (runner base), BaseCucumberSteps (step definition base with getDriver(), open(), $(), assertThat()), CucumberHooks (automatic driver lifecycle, metrics, screenshots, and report per scenario), CucumberStepLogger (Cucumber plugin that pipes Gherkin step names into the HTML report step timeline), CucumberContext (ThreadLocal Scenario holder); fully parallel-safe via ThreadLocal isolation; Scenario Outlines produce individual HTML report entries per example row; cucumber.properties support for IDE single-scenario execution; cucumber-java and cucumber-testng declared as optional dependencies — only pulled in by consumers who opt in

Changed​

  • TestExecutionListener — skips all onTest* callbacks for Cucumber runner tests (AbstractTestNGCucumberTests#runScenario) to prevent duplicate HTML report entries when running BDD and TestNG tests in the same suite
  • ExecutionHook.onTestEnd javadoc corrected: fires before driver quit, not after

[1.8.0] — 2026-04-16​

Added​

  • Self-Healing Locators — locators.selfHealing: true; when waitForVisible/waitForClickable times out the framework automatically tries fallback strategies derived from the original By descriptor: extract id from CSS #foo / XPath @id, name from CSS [name] / XPath @name, text from XPath text(), class from CSS .className, data-testid and placeholder attributes; healed tests get a ⚠ healed badge in the HTML report; target/healed-locators.json lists every healed locator for developer review
  • AI-Assisted Failure Analysis — ai.failureAnalysis: true + ai.apiKey: ${CLAUDE_API_KEY}; on test failure calls claude-haiku-4-5-20251001 (configurable via ai.model) with error, stack trace, step log, URL, and page title; the plain-English root-cause analysis + suggested fix is embedded in the HTML report failure detail panel; call bounded by ai.timeoutSeconds (default 20s); fully non-blocking — never affects suite outcome
  • Flakiness Prediction — reads last N JSON run files from target/metrics-history/; classifies each test as STABLE (<10% failure rate), WATCH (10–threshold%), or HIGH (≥threshold); results shown in a new Flakiness Radar card on the HTML report Dashboard; exported to target/flakiness-report.json; optional flakiness.failOnHighFlakiness: true CI gate

[1.7.0] — 2026-04-16​

Added​

  • Trace Viewer — tracing.enabled: true in selenium-boot.yml generates a self-contained HTML trace file per failed test at target/traces/{ClassName}/{testMethod}-trace.html; the file embeds a clickable step timeline (each step shows its screenshot on click), a final-state screenshot taken at the moment of failure, the error message, and full stack trace; zero CDN dependencies — all CSS/JS are inlined; captureOnPass: true option to generate traces for passing tests too; HTML report shows a "View Trace" link in the failure detail panel

[1.6.0] — 2026-04-16​

Added​

  • Visual regression testing — VisualAssert.assertScreenshot(name) pixel-by-pixel screenshot comparison; baseline auto-created on first run; diff image written to target/visual-diffs/; VisualTolerance.of(n) for configurable pixel-difference tolerance; -DupdateBaselines=true system property forces baseline regeneration; configurable dirs via visual.baselineDir / visual.diffDir in selenium-boot.yml
  • Mobile device emulation — DeviceEmulator.emulate("iPhone 14") / emulateDevice() + resetDevice() in BasePage/BaseTest; full CDP emulation on Chrome/Edge (viewport, device scale factor, user-agent); window-resize + JS UA override fallback on Firefox; 6 built-in profiles: iPhone 14, iPhone SE, Pixel 7, Galaxy S23, iPad, iPad Pro 12; register custom profiles via DeviceProfiles.register()
  • Clipboard helpers — ClipboardHelper.write() / read() / clear() backed by a reliable JS global store (window.__seleniumBootClipboard); async native clipboard attempted best-effort
  • GeoLocation mock — GeoLocation.set(lat, lon) / clear(); CDP Emulation.setGeolocationOverride on Chrome/Edge; navigator.geolocation JS override fallback on Firefox
  • Network interception — NetworkMock.stub(urlPattern) with fluent StubBuilder; glob patterns (**/api/**); configurable response body, content-type, status code, and delay; auto-cleared after each test
  • Browser storage helpers — StorageHelper.localStorage(), sessionStorage(), cookies() — read/write/clear browser storage from tests without JS boilerplate
  • Fluent Locator API — $(css) / $(By) returning a chainable Locator; methods: filter(), withText(), within(), nth(); auto-wait terminal actions: click(), type(), getText(), isVisible(), count(), element(), elements()
  • Web-First Assertions — assertThat(By) / assertThat(Locator) returning LocatorAssert; auto-retrying assertions: isVisible(), isHidden(), isEnabled(), hasText(), containsText(), hasValue(), hasAttribute(), hasClass(), count()

[1.3.0] — 2026-04-07​

Added​

  • Shadow DOM helpers — ShadowDom utility + 7 BasePage protected methods (shadowFind, shadowFindAll, shadowClick, shadowType, shadowGetText, shadowPierce, shadowExists)
  • Alert handling fix — set unhandledPromptBehavior: ignore on all driver providers so native alerts stay open; BasePage.getAndAcceptAlert() convenience method
  • Component-aware waits — WaitEngine.waitForAngular() (Angular 2+ testability API + AngularJS 1.x fallback) and WaitEngine.waitForReactHydration() (React 18/17/16 fiber detection, Next.js aware)
  • Enhanced HTML report — pass rate gauge card, donut chart (Chart.js), retry badges, expandable inline error message + stack trace per failed row, filter buttons (All / Passed / Failed / Skipped / Flaky), text search, dark mode toggle, slowest-5 tests section
  • JUnit XML error details — <failure message> and element text now contain the actual assertion message and full stack trace instead of a generic placeholder
  • Allure adapter — opt-in Allure 2 result file generation; set reporting.allureEnabled: true in selenium-boot.yml; produces target/allure-results/{uuid}-result.json per test
  • Slack / Teams notifications — configure notifications.slack.webhookUrl and/or notifications.teams.webhookUrl; post-suite summary sent automatically; notifyOnFailureOnly option
  • @DependsOnApi — method- or class-level annotation; skips test before browser opens if the specified HTTP endpoint is unreachable; repeatable (multiple URLs, all must be up); result cached per suite to avoid redundant probes

[1.1.1] — 2026-03-28​

Added​

  • Schema validation — ApiResponse.assertSchema("schemas/user.json") validates response body against a JSON Schema (Draft-07); requires com.networknt:json-schema-validator:1.4.3 as consumer dependency
  • @UseAuth annotation — apply a named auth strategy from api.auth config block to any test method/class
  • ApiAuth.oauth2() — OAuth2 client credentials flow; token fetched on first use and cached until expiry
  • ApiClient.setGlobalAuth() / clearGlobalAuth() — suite-level auth set once, applied to every request automatically; cleared by framework after each test

[1.1.0] — 2026-03-25​

Added​

  • 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; per-request auth; auto step-logging
  • ApiResponse — JSONPath extraction ($.user.id), asObject(Class), fluent assertions (assertStatus, assertJson, assertBodyContains)
  • ApiAuth — bearerToken(token), basicAuth(user, pass)
  • ScenarioContext — thread-local in-test store; ctx().set/get; auto-cleared after each test
  • SuiteContext — global thread-safe store for cross-test state sharing; suiteCtx().set/get
  • apiClient(), ctx(), suiteCtx() added to BaseTest for hybrid UI+API tests

[0.10.0] — 2026-03-22​

Added​

  • @TestData — declarative test data injection via annotation; loads .json, .yml, .yaml from src/test/resources/testdata/; env-specific override when -Denv=<profile> is set; getTestData() returns Map<String, Object> in BaseTest
  • Browser matrix — browser.matrix: [chrome, firefox, edge] in YAML runs all tests on all browsers in one invocation; Browser column added to HTML report; per-browser TEST-selenium-boot-<browser>.xml for Jenkins matrix view
  • SessionCache — global (cross-thread) authenticated session store; store("name") captures cookies + localStorage; restore("name") applies them into the current driver and refreshes; invalidate() / clear() for teardown
  • SoftAssert — softAssert().that(condition, "message") collects assertion failures without throwing; framework flushes at onTestSuccess; each failure logged as FAIL step entry; single screenshot at flush time; test marked FAILED with combined message

[0.9.6] — 2026-03-21​

Added​

  • DownloadManager browser auto-configuration — Chrome sets download.default_directory via experimental prefs; Firefox sets FirefoxProfile download preferences; both skipped when execution.mode: remote
  • File upload helper — BasePage.upload(By, String) resolves absolute → classpath → project-root; CI-safe absolute path sent to Selenium

[0.9.5] — 2026-03-21​

Added​

  • ConsoleErrorCollector auto-integration — JS shim auto-injected on every open() call when browser.captureConsoleErrors: true; errors auto-collected at test end as WARN step entries in the HTML report
  • failOnConsoleErrors enforcement — passing test with JS errors is marked FAILED when browser.failOnConsoleErrors: true
  • StepStatus.WARN — new step status for JS error entries

[0.9.4] — 2026-03-20​

Added​

  • iFrame helpers expanded — withinFrameName(String nameOrId, Runnable action) added to BasePage
  • Nested frame support — withinFrame, withinFrameIndex, withinFrameName now use a thread-local depth counter; inner calls restore to parentFrame(), the outermost call restores to defaultContent()

[0.9.3] — 2026-03-20​

Fixed​

  • Alert methods use this.driver — acceptAlert, dismissAlert, getAlertText, typeInAlert in BasePage now build their WebDriverWait from this.driver (the driver passed into the page object constructor) instead of WaitEngine / DriverManager.getDriver(), eliminating the driver-mismatch that caused NoAlertPresentException in precondition context
  • @PreCondition error message — PreConditionRunner now unwraps InvocationTargetException to expose the real cause, so the failure message is meaningful instead of showing "null"

[0.9.2] — 2026-03-20​

Fixed​

  • @PreCondition failure no longer triggers retry — TestExecutionListener now catches precondition exceptions and re-throws as SkipException; the test is marked SKIPPED (not FAILED), the retry analyzer is not called, and no second browser is opened
  • maxAttempts: 0 now respected in YAML — SeleniumBootConfig.Retry.maxAttempts changed from int (default 1) to nullable Integer; the defaults loader now only applies a programmatic override when the value was not set at all (was null), not when explicitly set to 0

[0.9.1] — 2026-03-19​

Fixed​

  • Alert helpers now wait — acceptAlert, dismissAlert, getAlertText, typeInAlert in BasePage use WaitEngine.waitForAlert() instead of raw driver.switchTo().alert(), preventing NoAlertPresentException on slow pages

Added​

  • WaitEngine.waitForAlert() — explicit wait for browser alert presence
  • BasePage.smartFind(By primary, By... fallbacks) — convenience wrapper around SmartLocator.find() for use inside page objects without passing the driver manually

[0.9.0] — 2026-03-18​

Added​

  • 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)

[0.8.0] — 2026-03-17​

Added​

  • BasePage — page object base class with click, type, getText, getAttribute, isDisplayed
  • iFrame helpers — withinFrame(By, Runnable) and withinFrameIndex(int, Runnable) in BasePage
  • File upload helper — upload(By, String) in BasePage, resolves classpath and relative paths
  • SmartLocator — tries multiple locator strategies in order, returns first visible element
  • DownloadManager — waitForFile, waitForAnyFile, clearDownloads with partial-download detection
  • ConsoleErrorCollector — JS console error capture via WebDriver logs (Chrome) or injected shim (Firefox)
  • @PreCondition — session-aware pre-conditions with automatic cookie + localStorage caching
  • @ConditionProvider — marks provider methods in BaseConditions subclasses
  • BaseConditions — base class for condition providers, gives getDriver(), open(), click(), type()
  • @SeleniumBootApi — annotation marking stable public API with since version
  • FrameworkVersion — runtime version access and requireAtLeast() compatibility check
  • IncompatiblePluginException — thrown when plugin version requirements are not met
  • minFrameworkVersion() — new method on SeleniumBootPlugin for version compatibility declarations
  • Config additions — browser.downloadDir, browser.captureConsoleErrors, browser.failOnConsoleErrors

[0.7.0] — 2026-03-16​

Added​

  • Browser lifecycle control — browser.lifecycle: per-test | per-suite setting
  • Per-suite driver management — browser stays open across tests when per-suite is configured
  • Step logging — StepLogger.step() API for named test steps with optional screenshots and status badges
  • Step timeline — Step-by-step execution timeline in the HTML report detail panel
  • Tabbed HTML report — Left sidebar navigation with Dashboard, Test Cases, and Failures tabs
  • Failures tab — Pre-expanded failure details for faster debugging
  • Inline step screenshots — Base64-embedded step screenshots with lightbox on click

Changed​

  • HTML report overhauled with tab-based layout and collapsible test rows
  • Screenshot lightbox now opens full-size correctly

[0.6.0] — 2025-12-01​

Added​

  • Advanced HTML reporting — Dashboard with metrics cards, test case table, retry summary
  • Donut chart — Pass/fail/skip distribution chart on Dashboard tab
  • Slowest tests — Top-5 slowest tests ranked by duration
  • Pass rate gauge — Colour-coded pass rate percentage card
  • Retry badge — ↻ Nx badge on retried tests in the table

Changed​

  • Screenshots embedded as Base64 — report is now a single self-contained file

[0.5.0] — 2025-10-15​

Added​

  • Retry support — retry.enabled + retry.maxAttempts in selenium-boot.yml
  • @Retryable annotation — per-method retry override
  • RetryAnnotationTransformer — auto-registered via Java SPI, zero config
  • Retry metrics — retry counts tracked in ExecutionMetrics and exported to JSON

[0.4.0] — 2025-08-20​

Added​

  • WaitEngine — fluent explicit wait API (waitForVisible, waitForClickable, waitForText, etc.)
  • Timeout override — getWait(seconds) for per-call timeout override
  • waitForStaleness — wait for DOM element replacement after AJAX reload

[0.3.0] — 2025-06-10​

Added​

  • BasePage — page object base class with click, type, getText, isDisplayed, getAttribute
  • Parallel execution — parallel.enabled + parallel.threadCount configuration
  • Session semaphore — browser.maxActiveSessions cap on concurrent browser instances
  • JUnit XML reporter — target/surefire-reports/TEST-SeleniumBoot.xml

[0.2.0] — 2025-04-05​

Added​

  • BaseTest — test base class with open(), open(path), getDriver(), getWait()
  • SeleniumBootConfig — YAML configuration loader (selenium-boot.yml)
  • DriverManager — ThreadLocal WebDriver lifecycle management
  • Automatic driver setup — WebDriverManager integration, no manual driver downloads
  • Headless mode — browser.headless: true
  • Basic HTML report — pass/fail/skip counts and duration
  • Screenshot on failure — automatic capture, embedded in report

[0.1.0] — 2025-02-01​

Added​

  • Initial release
  • Chrome and Firefox support
  • Basic TestNG integration
  • selenium-boot.yml configuration file discovery