Changelog
All notable changes to Selenium Boot are documented here.
[3.3.0] — 2026-08-15
Fixed
execution.parallelvalidation now matches TestNG's own parallel modes —testsandinstancesare legitimate TestNG modes that flow straight through toXmlSuite.setParallel()and behave exactly likemethods/classesdownstream, 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'sXmlSuite.ParallelModeenum directly, sonone,methods,classes,tests, andinstancesare 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
WaitEngineconditions, consistent with the existingwaitFor*naming:waitForAttribute(By, attribute, value)— waits for an exact attribute match (seewaitForAttributeContainsfor a substring match).waitForUrlMatches(String regex)— waits for the current URL to match a regular expression (seewaitForUrlContainsfor a substring match).waitForTextMatches(By, String regex)— waits for an element's visible text to match a regular expression.- Purely additive to the
@SeleniumBootApisurface — 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.dirsystem property (defaulttarget). 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. NewReportPathshelper centralizes path resolution.
[3.1.0] — 2026-06-25
Added
- Accessibility-first locators — Playwright-style semantic locators available on
BaseTestandBasePage: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 explicitrole="…"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-waitLocatorchain — noThread.sleep, no explicit waits. toBy()escape hatch — every semantic locator can return its synthesized SeleniumByfor interop with raw Selenium orSmartLocator.- Configurable test-id attribute —
locators.testIdAttributeinselenium-boot.yml(defaultdata-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 testequivalents for allmvncommands - JUnit XML auto-detection —
JUnitXmlReporternow detects the active build tool at runtime: writes tobuild/test-results/test/(Gradle) when only abuild/directory exists, ortarget/surefire-reports/(Maven) otherwise; override with-Dseleniumboot.reports.dir=system property - Cross-build-tool version reporting —
FrameworkVersion.get()now readsImplementation-Versionfrom the JAR'sMANIFEST.MFas the primary source (works with both Maven and Gradle); falls back toMETA-INF/maven/.../pom.properties(Maven-only) and then"0.0.0";maven-jar-pluginconfigured withaddDefaultImplementationEntries: trueto populate the manifest on every Maven build
[2.5.0] — 2026-06-20
Added
- Accessibility Assertions (axe-core) —
accessibility()inBaseTestandBaseJUnit5Testruns 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 detailedAssertionErroron 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 rawAccessibilityResultfor custom inspection without asserting;result.violations(),result.violationsAtLevel(Impact.SERIOUS),result.passCount()Impactenum with ordering:CRITICAL > SERIOUS > MODERATE > MINOR;Impact.fromString(str)parses axe-core impact stringsAccessibilityResult,AccessibilityViolation,AccessibilityViolation.NodeDetailall available viaaccessibility().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()— rawPerformanceMetricsaccess 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 panelPerformanceAssert,PerformanceMetrics,PerformanceCollectorall available viaclock()pattern inBaseTestandBaseJUnit5Test
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.ymlin 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
@quarantinetag to a scenario in the.featurefile; (2) list entries inselenium-quarantine.ymlusing 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.enabledflag — set tofalseto 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
@TestDatasources —@TestDatanow acceptscsv:,excel:, anddb:prefixes in addition to the existing JSON/YAML files;sheetattribute selects an Excel worksheet;rowattribute picks the zero-based data row (header excluded); type coercion applied automatically (integers, doubles, booleans); Apache POI required for Excel (addpoi-ooxml:5.2.5to 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 thedatabaseconfig block; first result row loaded; participates in per-test connection lifecycle TestClock—clock().set("2030-01-01T00:00:00Z")injects a JSDateoverride into the browser;clock().advance(Duration.ofDays(30))fast-forwards relative to the current mock;clock().reset()restores real time; all three available viaclock()inBaseTestandBaseJUnit5Test; auto-reset called automatically after every test (pass, fail, skip)clockconfig block:clock.injectHeader/clock.headerNamefor 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;BrowserStackProviderbuilds W3Cbstack:optionscapabilities from YAML config; supports desktop (os,osVersion,browser,browserVersion) and mobile (device,realMobile); rawbstack:optionsoverrides viacapabilitiesmap; zero test-code change — all framework features work identically - Sauce Labs integration —
execution.mode: saucelabs;SauceLabsProviderbuilds W3Csauce:optionscapabilities; three regions supported:us-west-1,eu-central,apac-southeast; rawsauce:optionsoverrides viacapabilitiesmap - 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;nullwhen 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