From ebdb60b0a3f799e83803fc1850f685f470bd09a7 Mon Sep 17 00:00:00 2001 From: "Alex \"Blex\" B" <45384811+AB-xdev@users.noreply.github.com> Date: Tue, 14 Jul 2026 17:01:06 +0200 Subject: [PATCH 01/26] Update CONTRIBUTING.md Update recommended setup --- CONTRIBUTING.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2c7b025..c77eab3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,14 +23,15 @@ You should have the following things installed: * Maven (Note that the [Maven Wrapper](https://maven.apache.org/wrapper/) is shipped with the repo) ### Recommended setup -* Install ``IntelliJ`` (Community Edition is sufficient) - * Install the following plugins: - * [Save Actions](https://plugins.jetbrains.com/plugin/22113) - Provides save actions, like running the formatter or adding ``final`` to fields - * [SonarLint](https://plugins.jetbrains.com/plugin/7973-sonarlint) - CodeStyle/CodeAnalysis - * You may consider disabling telemetry in the settings under ``Tools > Sonarlint -> About`` - * [Checkstyle-IDEA](https://plugins.jetbrains.com/plugin/1065-checkstyle-idea) - CodeStyle/CodeAnalysis +* Install `IntelliJ` + * Recommended setup actions + * Disable not needed plugins + * Disable [telemetry](https://www.jetbrains.com/help/idea/settings-usage-statistics.html) + * Consider [disabling the integrated webserver for security reasons](https://intellij-support.jetbrains.com/hc/en-us/community/posts/8125278285586-Internal-Local-ports-63342-6942?page=1#community_comment_8141506876562) using `-Didea.builtin.server.disabled=true` + * Configure the available memory * Import the project - * Ensure that everything is encoded in ``UTF-8`` + * You will get prompted to install the required plugins + * Ensure that everything is encoded in `UTF-8` * Ensure that the JDK/Java-Version is correct From 4dc1db8168698f69b147261da2ee21a478a190f4 Mon Sep 17 00:00:00 2001 From: "Alex \"Blex\" B" <45384811+AB-xdev@users.noreply.github.com> Date: Tue, 14 Jul 2026 17:18:14 +0200 Subject: [PATCH 02/26] Update CONTRIBUTING.md This options crashes the build --- CONTRIBUTING.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c77eab3..6e9dde5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,7 +27,6 @@ You should have the following things installed: * Recommended setup actions * Disable not needed plugins * Disable [telemetry](https://www.jetbrains.com/help/idea/settings-usage-statistics.html) - * Consider [disabling the integrated webserver for security reasons](https://intellij-support.jetbrains.com/hc/en-us/community/posts/8125278285586-Internal-Local-ports-63342-6942?page=1#community_comment_8141506876562) using `-Didea.builtin.server.disabled=true` * Configure the available memory * Import the project * You will get prompted to install the required plugins From 4fb1a7e3e80822a380661ffa753c5a10ca3296bb Mon Sep 17 00:00:00 2001 From: "Alex \"Blex\" B" <45384811+AB-xdev@users.noreply.github.com> Date: Wed, 22 Jul 2026 11:11:54 +0200 Subject: [PATCH 03/26] Delete .idea/PMDPlugin.xml Fixes #26 --- .idea/PMDPlugin.xml | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 .idea/PMDPlugin.xml diff --git a/.idea/PMDPlugin.xml b/.idea/PMDPlugin.xml deleted file mode 100644 index 0936e51..0000000 --- a/.idea/PMDPlugin.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - \ No newline at end of file From fc631b210ab3cf80744fd32c465490efc0c5aafd Mon Sep 17 00:00:00 2001 From: "Alex \"Blex\" B" <45384811+AB-xdev@users.noreply.github.com> Date: Wed, 22 Jul 2026 11:12:19 +0200 Subject: [PATCH 04/26] Delete .idea/PMDPlugin.xml --- .idea/PMDPlugin.xml | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 .idea/PMDPlugin.xml diff --git a/.idea/PMDPlugin.xml b/.idea/PMDPlugin.xml deleted file mode 100644 index 0936e51..0000000 --- a/.idea/PMDPlugin.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - \ No newline at end of file From 8e9182de91b1834ca393d23496428e375732197c Mon Sep 17 00:00:00 2001 From: AB Date: Wed, 22 Jul 2026 11:41:35 +0200 Subject: [PATCH 05/26] Prevent creating variants of Util classes like "DBUtils" or "DBUtility" --- .config/checkstyle/checkstyle.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/checkstyle/checkstyle.xml b/.config/checkstyle/checkstyle.xml index 94a22c6..99b29e8 100644 --- a/.config/checkstyle/checkstyle.xml +++ b/.config/checkstyle/checkstyle.xml @@ -81,7 +81,7 @@ - + From 74e4ed9efcab40bba843215bb4ec6bec827740e9 Mon Sep 17 00:00:00 2001 From: XDEV Renovate Bot Date: Thu, 23 Jul 2026 06:22:57 +0000 Subject: [PATCH 06/26] Update dependency com.mycila:license-maven-plugin to v5.1.1 --- template-placeholder/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template-placeholder/pom.xml b/template-placeholder/pom.xml index c1cb551..9a455a9 100644 --- a/template-placeholder/pom.xml +++ b/template-placeholder/pom.xml @@ -68,7 +68,7 @@ com.mycila license-maven-plugin - 5.0.0 + 5.1.1 ${project.organization.url} From df60de3e16c8274afc947db6fd7351ba46c94b8a Mon Sep 17 00:00:00 2001 From: XDEV Renovate Bot Date: Sat, 25 Jul 2026 06:06:42 +0000 Subject: [PATCH 07/26] Update dependency org.codehaus.mojo:flatten-maven-plugin to v1.8.0 --- template-placeholder/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template-placeholder/pom.xml b/template-placeholder/pom.xml index c1cb551..5ec5217 100644 --- a/template-placeholder/pom.xml +++ b/template-placeholder/pom.xml @@ -147,7 +147,7 @@ org.codehaus.mojo flatten-maven-plugin - 1.7.3 + 1.8.0 ossrh From ae1b42705d02def918a26b15083710400a47a1f1 Mon Sep 17 00:00:00 2001 From: AB Date: Mon, 27 Jul 2026 08:43:12 +0200 Subject: [PATCH 08/26] Disable UnusedTryResourceShouldBeUnnamed This is only relevant for projects that are using Java 25+ which most of libraries are not yet built against --- .config/checkstyle/checkstyle.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.config/checkstyle/checkstyle.xml b/.config/checkstyle/checkstyle.xml index 99b29e8..dcc19b4 100644 --- a/.config/checkstyle/checkstyle.xml +++ b/.config/checkstyle/checkstyle.xml @@ -146,7 +146,8 @@ - + + From eaa7a17d119aca0d783dd03fc9b13487a0e5c800 Mon Sep 17 00:00:00 2001 From: XDEV Renovate Bot Date: Mon, 27 Jul 2026 06:55:39 +0000 Subject: [PATCH 09/26] Update dependency com.puppycrawl.tools:checkstyle to v13.9.0 --- pom.xml | 2 +- template-placeholder/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9642b3f..333c1c2 100644 --- a/pom.xml +++ b/pom.xml @@ -45,7 +45,7 @@ com.puppycrawl.tools checkstyle - 13.8.0 + 13.9.0 diff --git a/template-placeholder/pom.xml b/template-placeholder/pom.xml index 2ffc513..202e05b 100644 --- a/template-placeholder/pom.xml +++ b/template-placeholder/pom.xml @@ -215,7 +215,7 @@ com.puppycrawl.tools checkstyle - 13.8.0 + 13.9.0 From d7bb00981e20e363c9a2300024cb882fab994349 Mon Sep 17 00:00:00 2001 From: AB Date: Mon, 3 Aug 2026 08:43:21 +0200 Subject: [PATCH 10/26] Update redirect links --- CONTRIBUTING.md | 4 ++-- README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6e9dde5..ee364fd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ We would absolutely love to get the community involved, and we welcome any form * **Send pull requests**
If you want to contribute code, check out the development instructions below. * However when contributing larger new features, please first discuss the change you wish to make via issue with the owners of this repository before making it.
Otherwise your work might be rejected and your effort was pointless. -We also encourage you to read the [contribution instructions by GitHub](https://docs.github.com/en/get-started/quickstart/contributing-to-projects). +We also encourage you to read the [contribution instructions by GitHub](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project). ## Developing @@ -20,7 +20,7 @@ We also encourage you to read the [contribution instructions by GitHub](https:// You should have the following things installed: * Git * Java 25 - should be as unmodified as possible (Recommended: [Eclipse Adoptium](https://adoptium.net/temurin/releases/)) -* Maven (Note that the [Maven Wrapper](https://maven.apache.org/wrapper/) is shipped with the repo) +* Maven (Note that the [Maven Wrapper](https://maven.apache.org/tools/wrapper/) is shipped with the repo) ### Recommended setup * Install `IntelliJ` diff --git a/README.md b/README.md index 3b97901..e97be21 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [Installation guide for the latest release](https://github.com/xdev-software/template-placeholder/releases/latest#Installation) ## Support -If you need support as soon as possible and you can't wait for any pull request, feel free to use [our support](https://xdev.software/en/services/support). +If you need support as soon as possible and you can't wait for any pull request, feel free to use [our support](https://xdev.software/en/services-products/support). ## Contributing See the [contributing guide](./CONTRIBUTING.md) for detailed instructions on how to get started with our project. From 05f54ff535e6b14a6a6d80f3ff683b3fc514d596 Mon Sep 17 00:00:00 2001 From: AB Date: Mon, 3 Aug 2026 08:47:07 +0200 Subject: [PATCH 11/26] Stackoverflow links return 403 when validated --- .github/.lycheeignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/.lycheeignore b/.github/.lycheeignore index dc88a07..217b0ae 100644 --- a/.github/.lycheeignore +++ b/.github/.lycheeignore @@ -1,3 +1,4 @@ # Ignorefile for broken link check localhost mvnrepository.com +stackoverflow.com From 19fce86358264d51c5dbbdb474931287625f9b1c Mon Sep 17 00:00:00 2001 From: AB Date: Mon, 3 Aug 2026 09:19:46 +0200 Subject: [PATCH 12/26] CS 13.9 remove removed JavadocStyle and replace it with JavadocContentLocation --- .config/checkstyle/checkstyle.xml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.config/checkstyle/checkstyle.xml b/.config/checkstyle/checkstyle.xml index dcc19b4..b585880 100644 --- a/.config/checkstyle/checkstyle.xml +++ b/.config/checkstyle/checkstyle.xml @@ -87,9 +87,7 @@ - - - + From 25c8893930922162b91150eeb6023d79c81dccb2 Mon Sep 17 00:00:00 2001 From: AB Date: Mon, 3 Aug 2026 14:15:55 +0200 Subject: [PATCH 13/26] Update pmd-x.xml --- .idea/pmd-x.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.idea/pmd-x.xml b/.idea/pmd-x.xml index 260e454..7b3b48f 100644 --- a/.idea/pmd-x.xml +++ b/.idea/pmd-x.xml @@ -10,6 +10,7 @@ From bc90eb704e7189136c3fedf393c7ce444b1d363d Mon Sep 17 00:00:00 2001 From: AB Date: Tue, 4 Aug 2026 08:28:46 +0200 Subject: [PATCH 14/26] Fix redirect link --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ee364fd..390a0cf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ We would absolutely love to get the community involved, and we welcome any form ### Communication channels * Communication is primarily done using issues. -* If you need support as soon as possible and you can't wait for any pull request, feel free to use [our support](https://xdev.software/en/services/support). +* If you need support as soon as possible and you can't wait for any pull request, feel free to use [our support](https://xdev.software/en/services-products/support). * As a last resort measure or on otherwise important matter you may also [contact us directly](https://xdev.software/en/about-us/contact). ### Ways to help From 867b1fef77e8a7f8b1063ee5c227c437a752378f Mon Sep 17 00:00:00 2001 From: XDEV Renovate Bot Date: Fri, 7 Aug 2026 04:01:16 +0000 Subject: [PATCH 15/26] Update shogo82148/actions-create-release digest to 8674c0e --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6133d1a..dc0033e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -91,7 +91,7 @@ jobs: - name: Create Release id: create-release - uses: shogo82148/actions-create-release@6a396031bc74c57403da1018fec74d24c6aa03cd # v1 + uses: shogo82148/actions-create-release@8674c0ecee617c8dfb006526bcc22a362c70b88a # v1 with: tag_name: v${{ steps.version.outputs.release }} release_name: v${{ steps.version.outputs.release }} From 6b29b044554e3834ba067fc24e7aad64efc626a6 Mon Sep 17 00:00:00 2001 From: XDEV Renovate Bot Date: Sat, 8 Aug 2026 03:32:01 +0000 Subject: [PATCH 16/26] Update dependency org.junit.jupiter:junit-jupiter to v6.1.3 --- testcontainers-selenium/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testcontainers-selenium/pom.xml b/testcontainers-selenium/pom.xml index a719d12..a5c4f0f 100644 --- a/testcontainers-selenium/pom.xml +++ b/testcontainers-selenium/pom.xml @@ -78,7 +78,7 @@ org.junit.jupiter junit-jupiter - 6.1.2 + 6.1.3 test From 9be12abd04f2ef265cddf8e6a09762b1f86e3311 Mon Sep 17 00:00:00 2001 From: XDEV Renovate Bot Date: Mon, 10 Aug 2026 03:36:47 +0000 Subject: [PATCH 17/26] Update dependency com.puppycrawl.tools:checkstyle to v13.10.0 --- pom.xml | 2 +- template-placeholder/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 333c1c2..30343dc 100644 --- a/pom.xml +++ b/pom.xml @@ -45,7 +45,7 @@ com.puppycrawl.tools checkstyle - 13.9.0 + 13.10.0 diff --git a/template-placeholder/pom.xml b/template-placeholder/pom.xml index 202e05b..15881e9 100644 --- a/template-placeholder/pom.xml +++ b/template-placeholder/pom.xml @@ -215,7 +215,7 @@ com.puppycrawl.tools checkstyle - 13.9.0 + 13.10.0 From 33ba9e462c1ce9fded340bd2b2852cc2f1214f11 Mon Sep 17 00:00:00 2001 From: XDEV Renovate Bot Date: Tue, 11 Aug 2026 03:33:35 +0000 Subject: [PATCH 18/26] Update org.seleniumhq.selenium to v4.47.0 --- testcontainers-selenium-demo/pom.xml | 2 +- testcontainers-selenium/pom.xml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/testcontainers-selenium-demo/pom.xml b/testcontainers-selenium-demo/pom.xml index 06423b6..9fc8eb5 100644 --- a/testcontainers-selenium-demo/pom.xml +++ b/testcontainers-selenium-demo/pom.xml @@ -34,7 +34,7 @@ org.seleniumhq.selenium selenium-dependencies-bom - 4.46.0 + 4.47.0 pom import diff --git a/testcontainers-selenium/pom.xml b/testcontainers-selenium/pom.xml index a719d12..d118830 100644 --- a/testcontainers-selenium/pom.xml +++ b/testcontainers-selenium/pom.xml @@ -70,7 +70,7 @@ org.seleniumhq.selenium selenium-api - 4.46.0 + 4.47.0 provided @@ -90,7 +90,7 @@ org.seleniumhq.selenium selenium-remote-driver - 4.46.0 + 4.47.0 test @@ -108,13 +108,13 @@ org.seleniumhq.selenium selenium-support - 4.46.0 + 4.47.0 test org.seleniumhq.selenium selenium-firefox-driver - 4.46.0 + 4.47.0 test @@ -127,7 +127,7 @@ org.seleniumhq.selenium selenium-chrome-driver - 4.46.0 + 4.47.0 test From b2fae6dc5a76285b5dddeb6cc3354be2b142fca3 Mon Sep 17 00:00:00 2001 From: AB Date: Tue, 11 Aug 2026 13:57:56 +0200 Subject: [PATCH 19/26] Prepare for next release and fix CS * Rename `SeleniumUtils` to `SeleniumVersionDetector` * Update default Selenium version to `4.47.0` * Updated dependencies --- CHANGELOG.md | 5 + pom.xml | 2 +- testcontainers-selenium-demo/pom.xml | 4 +- testcontainers-selenium/pom.xml | 2 +- ...CapabilitiesBrowserWebDriverContainer.java | 2 +- .../containers/browser/SeleniumUtils.java | 119 ++------------ .../browser/SeleniumVersionDetector.java | 145 ++++++++++++++++++ 7 files changed, 166 insertions(+), 113 deletions(-) create mode 100644 testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/SeleniumVersionDetector.java diff --git a/CHANGELOG.md b/CHANGELOG.md index ac35994..7075ff5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 2.1.0 +* Rename `SeleniumUtils` to `SeleniumVersionDetector` +* Update default Selenium version to `4.47.0` +* Updated dependencies + # 2.0.2 * Extract wait strategy values into constants * Updated dependencies diff --git a/pom.xml b/pom.xml index ab316e4..7b9b5ef 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ software.xdev testcontainers-selenium-root - 2.0.3-SNAPSHOT + 2.1.0-SNAPSHOT pom diff --git a/testcontainers-selenium-demo/pom.xml b/testcontainers-selenium-demo/pom.xml index 06423b6..20ab796 100644 --- a/testcontainers-selenium-demo/pom.xml +++ b/testcontainers-selenium-demo/pom.xml @@ -7,11 +7,11 @@ software.xdev testcontainers-selenium-root - 2.0.3-SNAPSHOT + 2.1.0-SNAPSHOT testcontainers-selenium-demo - 2.0.3-SNAPSHOT + 2.1.0-SNAPSHOT jar diff --git a/testcontainers-selenium/pom.xml b/testcontainers-selenium/pom.xml index 1fca634..83ef71c 100644 --- a/testcontainers-selenium/pom.xml +++ b/testcontainers-selenium/pom.xml @@ -6,7 +6,7 @@ software.xdev testcontainers-selenium - 2.0.3-SNAPSHOT + 2.1.0-SNAPSHOT jar testcontainers-selenium diff --git a/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/CapabilitiesBrowserWebDriverContainer.java b/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/CapabilitiesBrowserWebDriverContainer.java index 4c92564..ce8249f 100644 --- a/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/CapabilitiesBrowserWebDriverContainer.java +++ b/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/CapabilitiesBrowserWebDriverContainer.java @@ -46,7 +46,7 @@ public CapabilitiesBrowserWebDriverContainer( { this(getStandardImageForCapabilities( capabilities, - SeleniumUtils.getClasspathSeleniumVersion(), + SeleniumVersionDetector.getClasspathSeleniumVersion(), browserDockerImages)); } diff --git a/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/SeleniumUtils.java b/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/SeleniumUtils.java index 77d5359..0c42856 100644 --- a/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/SeleniumUtils.java +++ b/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/SeleniumUtils.java @@ -15,131 +15,34 @@ */ package software.xdev.testcontainers.selenium.containers.browser; -import java.io.InputStream; -import java.net.URL; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Set; -import java.util.jar.Attributes; import java.util.jar.Manifest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** - * Utility methods for Selenium. - *

- * Forked from Testcontainers and enhanced with caching. - *

+ * @deprecated Renamed to {@link SeleniumVersionDetector} */ +@SuppressWarnings("checkstyle:IllegalIdentifierName") +@Deprecated(forRemoval = true) public final class SeleniumUtils { - private static final Logger LOG = LoggerFactory.getLogger(SeleniumUtils.class); - - // as of 2026-01 - public static final String DEFAULT_SELENIUM_VERSION = "4.45.0"; - private static String cachedVersion; - - private SeleniumUtils() - { - } + public static final String DEFAULT_SELENIUM_VERSION = SeleniumVersionDetector.DEFAULT_SELENIUM_VERSION; - /** - * Based on the JARs detected on the classpath, determine which version of selenium-api is available. - * - * @return the detected version of Selenium API, or DEFAULT_SELENIUM_VERSION if it could not be determined - */ public static String getClasspathSeleniumVersion() { - if(cachedVersion != null) - { - return cachedVersion; - } - cachedVersion = determineClasspathSeleniumVersion(); - return cachedVersion; + return SeleniumVersionDetector.getClasspathSeleniumVersion(); } public static synchronized String determineClasspathSeleniumVersion() { - if(cachedVersion != null) - { - return cachedVersion; - } - - final Set seleniumVersions = new HashSet<>(); - try - { - final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - final Enumeration manifests = classLoader.getResources("META-INF/MANIFEST.MF"); - - while(manifests.hasMoreElements()) - { - final URL manifestURL = manifests.nextElement(); - try(final InputStream is = manifestURL.openStream()) - { - final Manifest manifest = new Manifest(); - manifest.read(is); - - final String seleniumVersion = getSeleniumVersionFromManifest(manifest); - if(seleniumVersion != null) - { - seleniumVersions.add(seleniumVersion); - LOG.info("Selenium API version {} detected on classpath", seleniumVersion); - } - } - } - } - catch(final Exception e) - { - LOG.debug("Failed to determine Selenium-Version from selenium-api JAR Manifest", e); - } - - if(seleniumVersions.isEmpty()) - { - LOG.warn( - "Failed to determine Selenium version from classpath - will use default version of {}", - DEFAULT_SELENIUM_VERSION - ); - return DEFAULT_SELENIUM_VERSION; - } - - final String foundVersion = seleniumVersions.iterator().next(); - if(seleniumVersions.size() > 1) - { - LOG.warn( - "Multiple versions of Selenium API found on classpath - will select {}, but this may not be reliable", - foundVersion - ); - } - - return foundVersion; + return SeleniumVersionDetector.determineClasspathSeleniumVersion(); } - /** - * Read Manifest to get Selenium Version. - * - * @param manifest manifest - * @return Selenium Version detected - */ public static String getSeleniumVersionFromManifest(final Manifest manifest) { - String seleniumVersion = null; - final Attributes buildInfo = manifest.getAttributes("Build-Info"); - if(buildInfo != null) - { - seleniumVersion = buildInfo.getValue("Selenium-Version"); - } - - // Compatibility Selenium > 3.X - if(seleniumVersion == null) - { - final Attributes seleniumInfo = manifest.getAttributes("Selenium"); - if(seleniumInfo != null) - { - seleniumVersion = seleniumInfo.getValue("Selenium-Version"); - } - } - return seleniumVersion; + return SeleniumVersionDetector.getSeleniumVersionFromManifest(manifest); + } + + private SeleniumUtils() + { } } diff --git a/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/SeleniumVersionDetector.java b/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/SeleniumVersionDetector.java new file mode 100644 index 0000000..ff3e5f6 --- /dev/null +++ b/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/SeleniumVersionDetector.java @@ -0,0 +1,145 @@ +/* + * Copyright © 2024 XDEV Software (https://xdev.software) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package software.xdev.testcontainers.selenium.containers.browser; + +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * Version detection methods for Selenium. + *

+ * Forked from Testcontainers SeleniumUtils and enhanced with caching. + *

+ */ +public final class SeleniumVersionDetector +{ + private static final Logger LOG = LoggerFactory.getLogger(SeleniumVersionDetector.class); + + // as of 2026-08 + public static final String DEFAULT_SELENIUM_VERSION = "4.47.0"; + private static String cachedVersion; + + /** + * Based on the JARs detected on the classpath, determine which version of selenium-api is available. + * + * @return the detected version of Selenium API, or DEFAULT_SELENIUM_VERSION if it could not be determined + */ + public static String getClasspathSeleniumVersion() + { + if(cachedVersion != null) + { + return cachedVersion; + } + cachedVersion = determineClasspathSeleniumVersion(); + return cachedVersion; + } + + public static synchronized String determineClasspathSeleniumVersion() + { + if(cachedVersion != null) + { + return cachedVersion; + } + + final Set seleniumVersions = new HashSet<>(); + try + { + final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + final Enumeration manifests = classLoader.getResources("META-INF/MANIFEST.MF"); + + while(manifests.hasMoreElements()) + { + final URL manifestURL = manifests.nextElement(); + try(final InputStream is = manifestURL.openStream()) + { + final Manifest manifest = new Manifest(); + manifest.read(is); + + final String seleniumVersion = getSeleniumVersionFromManifest(manifest); + if(seleniumVersion != null) + { + seleniumVersions.add(seleniumVersion); + LOG.info("Selenium API version {} detected on classpath", seleniumVersion); + } + } + } + } + catch(final Exception e) + { + LOG.debug("Failed to determine Selenium-Version from selenium-api JAR Manifest", e); + } + + if(seleniumVersions.isEmpty()) + { + LOG.warn( + "Failed to determine Selenium version from classpath - will use default version of {}", + DEFAULT_SELENIUM_VERSION + ); + return DEFAULT_SELENIUM_VERSION; + } + + final String foundVersion = seleniumVersions.iterator().next(); + if(seleniumVersions.size() > 1) + { + LOG.warn( + "Multiple versions of Selenium API found on classpath - will select {}, but this may not be reliable", + foundVersion + ); + } + + return foundVersion; + } + + /** + * Read Manifest to get Selenium Version. + * + * @param manifest manifest + * @return Selenium Version detected + */ + public static String getSeleniumVersionFromManifest(final Manifest manifest) + { + String seleniumVersion = null; + final Attributes buildInfo = manifest.getAttributes("Build-Info"); + if(buildInfo != null) + { + seleniumVersion = buildInfo.getValue("Selenium-Version"); + } + + // Compatibility Selenium > 3.X + if(seleniumVersion == null) + { + final Attributes seleniumInfo = manifest.getAttributes("Selenium"); + if(seleniumInfo != null) + { + seleniumVersion = seleniumInfo.getValue("Selenium-Version"); + } + } + return seleniumVersion; + } + + private SeleniumVersionDetector() + { + } +} From 91891fb4a556370c3168c9d9a8885fd2fbe3febd Mon Sep 17 00:00:00 2001 From: AB Date: Tue, 11 Aug 2026 14:04:42 +0200 Subject: [PATCH 20/26] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a9f135b..f50622f 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,9 @@ A re-implementation of [Testcontainer Selenium/WebDriver](https://java.testconta * No VNC Server started in the browser container (unless explicitly stated) → Saves memory * Uses [Selenium's implementation](https://github.com/SeleniumHQ/docker-selenium/tree/trunk/Video) and isn't [based](https://github.com/testcontainers/vnc-recorder) on [some python code from 2010](https://pypi.org/project/vnc2flv/#history) * Way more customization options for e.g. ``framerate``, ``codec``, ``preset`` ... - * Uses ``mkv`` as default recording format (wider support in comparison to ``flv``) + * Uses `mkv` as default recording format + * wider support in comparison to `flv` + * `mkv` allows incomplete recordings without file corruption * [Renders while saving the video](https://github.com/SeleniumHQ/docker-selenium/blob/4c572afd1173b5bd49fa2def3b54ea552fccee85/Video/video.sh#L126) (not when finished which takes additional time) * Stops the recorder before saving the file so that there is no way that [it runs forever](https://github.com/testcontainers/testcontainers-java/discussions/6229). * Automatically tries to select a alternative Selenium version for the docker image if it [doesn't exist](https://github.com/SeleniumHQ/docker-selenium/issues/1979). From 520bb73cffaab77c2b5d52e11f5d4d4d5bca6e65 Mon Sep 17 00:00:00 2001 From: AB Date: Tue, 11 Aug 2026 14:11:38 +0200 Subject: [PATCH 21/26] Fix order of WaitStrategies --- .../selenium/containers/browser/BrowserWebDriverContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/BrowserWebDriverContainer.java b/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/BrowserWebDriverContainer.java index ab87da7..f41dd41 100644 --- a/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/BrowserWebDriverContainer.java +++ b/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/BrowserWebDriverContainer.java @@ -133,9 +133,9 @@ public BrowserWebDriverContainer(final DockerImageName dockerImageName) protected WaitStrategy getDefaultWaitStrategy() { return new WaitAllStrategy() + .withStrategy(new HostPortWaitStrategy()) .withStrategy(new LogMessageWaitStrategy() .withRegEx(LOG_MSG_WAIT_STRATEGY_REGEX)) - .withStrategy(new HostPortWaitStrategy()) .withStartupTimeout(Duration.of(60, ChronoUnit.SECONDS)); } From 8bf4de797ef76d18d9904042a982065df7ad4e6b Mon Sep 17 00:00:00 2001 From: AB Date: Tue, 11 Aug 2026 14:42:48 +0200 Subject: [PATCH 22/26] Extract image name extraction logic --- CHANGELOG.md | 1 + .../browser/BrowserWebDriverContainer.java | 19 ++------ .../GenericContainerImageNameAccessor.java | 46 +++++++++++++++++++ ...GenericContainerImageNameAccessorTest.java | 37 +++++++++++++++ 4 files changed, 87 insertions(+), 16 deletions(-) create mode 100644 testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/GenericContainerImageNameAccessor.java create mode 100644 testcontainers-selenium/src/test/java/software/xdev/testcontainers/selenium/containers/browser/GenericContainerImageNameAccessorTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 7075ff5..8fc4ef9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # 2.1.0 * Rename `SeleniumUtils` to `SeleniumVersionDetector` +* Extract image name extraction logic * Update default Selenium version to `4.47.0` * Updated dependencies diff --git a/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/BrowserWebDriverContainer.java b/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/BrowserWebDriverContainer.java index f41dd41..1a4c515 100644 --- a/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/BrowserWebDriverContainer.java +++ b/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/BrowserWebDriverContainer.java @@ -16,8 +16,6 @@ package software.xdev.testcontainers.selenium.containers.browser; import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; @@ -27,12 +25,11 @@ import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.function.Supplier; @@ -82,8 +79,7 @@ public class BrowserWebDriverContainer WORKING_BROWSER_IMAGES_TRANSLATION = - Collections.synchronizedMap(new HashMap<>()); + protected static final Map WORKING_BROWSER_IMAGES_TRANSLATION = new ConcurrentHashMap<>(); public static final int SELENIUM_PORT = 4444; public static final int VNC_PORT = 5900; @@ -341,7 +337,6 @@ protected void configureVNC() } // region Validate image - // If testcontainers could implement the same method better or made stuff protected we wouldn't need reflection @SuppressWarnings("java:S3011") protected void validateImage() { @@ -355,16 +350,8 @@ protected void validateImage() // In this case try to look for alternative images try { - final Field fImage = GenericContainer.class.getDeclaredField("image"); - fImage.setAccessible(true); - final RemoteDockerImage remoteDockerImage = (RemoteDockerImage)fImage.get(this); - - final Method mGetImageName = RemoteDockerImage.class.getDeclaredMethod("getImageName"); - mGetImageName.setAccessible(true); - final DockerImageName currentImage = (DockerImageName)mGetImageName.invoke(remoteDockerImage); - this.setDockerImageName(WORKING_BROWSER_IMAGES_TRANSLATION.computeIfAbsent( - currentImage, + GenericContainerImageNameAccessor.getImageName(this), this::validateImageOrPickAlternative)); } catch(final Exception ex) diff --git a/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/GenericContainerImageNameAccessor.java b/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/GenericContainerImageNameAccessor.java new file mode 100644 index 0000000..bdf47c9 --- /dev/null +++ b/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/GenericContainerImageNameAccessor.java @@ -0,0 +1,46 @@ +package software.xdev.testcontainers.selenium.containers.browser; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Objects; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.images.RemoteDockerImage; +import org.testcontainers.utility.DockerImageName; + + +/** + * Extracts the {@link DockerImageName} from {@link GenericContainer} without pulling it. + *

+ * Uses reflection because there is no official way to access it. + *

+ */ +public final class GenericContainerImageNameAccessor +{ + // Cache to improve performance + private static boolean initialized; + private static Field fImage; + private static Method mGetImageName; + + public static DockerImageName getImageName(final GenericContainer container) throws Exception + { + if(!initialized) + { + fImage = GenericContainer.class.getDeclaredField("image"); + fImage.setAccessible(true); + + mGetImageName = RemoteDockerImage.class.getDeclaredMethod("getImageName"); + mGetImageName.setAccessible(true); + + initialized = true; + } + + final RemoteDockerImage remoteDockerImage = (RemoteDockerImage)fImage.get(container); + + return (DockerImageName)Objects.requireNonNull(mGetImageName.invoke(remoteDockerImage)); + } + + private GenericContainerImageNameAccessor() + { + } +} diff --git a/testcontainers-selenium/src/test/java/software/xdev/testcontainers/selenium/containers/browser/GenericContainerImageNameAccessorTest.java b/testcontainers-selenium/src/test/java/software/xdev/testcontainers/selenium/containers/browser/GenericContainerImageNameAccessorTest.java new file mode 100644 index 0000000..eaaeb8a --- /dev/null +++ b/testcontainers-selenium/src/test/java/software/xdev/testcontainers/selenium/containers/browser/GenericContainerImageNameAccessorTest.java @@ -0,0 +1,37 @@ +package software.xdev.testcontainers.selenium.containers.browser; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.concurrent.CompletableFuture; +import java.util.stream.Stream; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; + + +class GenericContainerImageNameAccessorTest +{ + static final String IMAGE = "alpine:3"; + static final DockerImageName DOCKER_IMAGE_NAME = DockerImageName.parse(IMAGE); + + @ParameterizedTest + @MethodSource + void reflectionStillWorks(final GenericContainer container) + { + assertEquals( + DOCKER_IMAGE_NAME, + assertDoesNotThrow(() -> GenericContainerImageNameAccessor.getImageName(container))); + } + + static Stream reflectionStillWorks() + { + return Stream.of( + new GenericContainer<>(IMAGE), + new GenericContainer<>(CompletableFuture.completedFuture(IMAGE))) + .map(Arguments::of); + } +} From 4e8120c2d3ca2e3a8e8ea9a6d660076c55477c9a Mon Sep 17 00:00:00 2001 From: AB Date: Tue, 11 Aug 2026 14:45:15 +0200 Subject: [PATCH 23/26] AMH --- .../GenericContainerImageNameAccessor.java | 15 +++++++++++++++ .../GenericContainerImageNameAccessorTest.java | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/GenericContainerImageNameAccessor.java b/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/GenericContainerImageNameAccessor.java index bdf47c9..08b7086 100644 --- a/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/GenericContainerImageNameAccessor.java +++ b/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/GenericContainerImageNameAccessor.java @@ -1,3 +1,18 @@ +/* + * Copyright © 2024 XDEV Software (https://xdev.software) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package software.xdev.testcontainers.selenium.containers.browser; import java.lang.reflect.Field; diff --git a/testcontainers-selenium/src/test/java/software/xdev/testcontainers/selenium/containers/browser/GenericContainerImageNameAccessorTest.java b/testcontainers-selenium/src/test/java/software/xdev/testcontainers/selenium/containers/browser/GenericContainerImageNameAccessorTest.java index eaaeb8a..e7075fe 100644 --- a/testcontainers-selenium/src/test/java/software/xdev/testcontainers/selenium/containers/browser/GenericContainerImageNameAccessorTest.java +++ b/testcontainers-selenium/src/test/java/software/xdev/testcontainers/selenium/containers/browser/GenericContainerImageNameAccessorTest.java @@ -1,3 +1,18 @@ +/* + * Copyright © 2024 XDEV Software (https://xdev.software) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package software.xdev.testcontainers.selenium.containers.browser; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; From 6ada825ba68ad8c8c918fea5749f67b50f3159cc Mon Sep 17 00:00:00 2001 From: AB Date: Tue, 11 Aug 2026 14:47:25 +0200 Subject: [PATCH 24/26] No longer a god :( --- .../selenium/containers/browser/BrowserWebDriverContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/BrowserWebDriverContainer.java b/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/BrowserWebDriverContainer.java index 1a4c515..d6c961a 100644 --- a/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/BrowserWebDriverContainer.java +++ b/testcontainers-selenium/src/main/java/software/xdev/testcontainers/selenium/containers/browser/BrowserWebDriverContainer.java @@ -63,7 +63,7 @@ /** * A chrome/firefox/custom container based on SeleniumHQ's standalone container sets. */ -@SuppressWarnings({"java:S119", "java:S2160", "PMD.GodClass"}) +@SuppressWarnings({"java:S119", "java:S2160"}) public class BrowserWebDriverContainer> extends GenericContainer implements TestLifecycleAware From a162508149196560c9da1041fca2ea7e5c31b64a Mon Sep 17 00:00:00 2001 From: AB Date: Tue, 11 Aug 2026 14:58:19 +0200 Subject: [PATCH 25/26] Disable docker checks for each run because we know that it always works --- .github/workflows/check-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-build.yml b/.github/workflows/check-build.yml index f7bd723..d62278e 100644 --- a/.github/workflows/check-build.yml +++ b/.github/workflows/check-build.yml @@ -48,7 +48,7 @@ jobs: ${{ runner.os }}-mvn-build- - name: Build with Maven - run: ./mvnw -B clean package -P run-integration-tests + run: ./mvnw -B clean package -P run-integration-tests -D checks.disable=true - name: Check for uncommited changes run: | From 53543b89fb8a2ceefa6585135d0770d5d99ef084 Mon Sep 17 00:00:00 2001 From: AB Date: Tue, 11 Aug 2026 15:09:23 +0200 Subject: [PATCH 26/26] Cache docker images to not always pull them on build --- .github/workflows/check-build.yml | 44 ++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/.github/workflows/check-build.yml b/.github/workflows/check-build.yml index d62278e..c4f0b8d 100644 --- a/.github/workflows/check-build.yml +++ b/.github/workflows/check-build.yml @@ -33,19 +33,31 @@ jobs: steps: - uses: actions/checkout@v7 - - name: Set up JDK - uses: actions/setup-java@v5 - with: - distribution: ${{ matrix.distribution }} - java-version: ${{ matrix.java }} - - - name: Cache Maven - uses: actions/cache@v6 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-mvn-build-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-mvn-build- + - parallel: + - name: Set up JDK + uses: actions/setup-java@v5 + with: + distribution: ${{ matrix.distribution }} + java-version: ${{ matrix.java }} + + - name: Cache Maven + uses: actions/cache@v6 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-mvn-build-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-mvn-build- + + - name: Docker Image Cache Restore + id: docker-image-cache-restore + uses: xdev-software/tci/.github/actions/docker-image-cache/restore@f686d444930db567aae0cbc8076694f8c886f479 # v4.1.0 + with: + # This cache could always change however because docker images can be changed remotely if the version is not fixated + # As a compromise it utilizes the hash of the pom files because when the dependencies stay the same + # the images should also be roughly the same + key: ${{ runner.os }}-check-build-docker-images-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-check-build-docker-images- - name: Build with Maven run: ./mvnw -B clean package -P run-integration-tests -D checks.disable=true @@ -68,6 +80,12 @@ jobs: exit 1 fi + - name: Docker Image Cache Save + uses: xdev-software/tci/.github/actions/docker-image-cache/save@f686d444930db567aae0cbc8076694f8c886f479 # v4.1.0 + with: + key: ${{ steps.docker-image-cache-restore.outputs.key }} + cache-hit: ${{ steps.docker-image-cache-restore.outputs.cache-hit }} + checkstyle: runs-on: ubuntu-latest if: ${{ github.event_name != 'pull_request' || !startsWith(github.head_ref, 'renovate/') }}