You are viewing a plain text version of this content. The canonical link for it is here.
Posted to geb-notifications@groovy.apache.org by cm...@apache.org on 2026/02/15 22:13:15 UTC
(groovy-geb) 01/03: fix codenarc violations.
This is an automated email from the ASF dual-hosted git repository.
cmarcum pushed a commit to branch task/geb-testcontainers
in repository https://gitbox.apache.org/repos/asf/groovy-geb.git
commit 0036f2ca9bfe1921be634341b5043a3a8f594478
Author: Carl Marcum <ca...@codebuilders.net>
AuthorDate: Sat Feb 14 16:01:02 2026 -0500
fix codenarc violations.
---
.../grails/plugin/geb/ContainerFileDetector.groovy | 2 +-
.../plugin/geb/ContainerGebTestDescription.groovy | 4 +-
.../plugin/geb/DefaultContainerFileDetector.groovy | 4 +-
.../plugin/geb/GrailsContainerGebExtension.groovy | 18 +-
.../grails/plugin/geb/GrailsGebSettings.groovy | 45 ++-
.../plugin/geb/WebDriverContainerHolder.groovy | 387 +++++++++++----------
.../geb/serviceloader/ServiceRegistry.groovy | 4 +-
.../grails/plugin/geb/support/BrowserType.groovy | 14 +-
.../geb/support/ContainerGebFileInputSource.groovy | 1 -
.../geb/support/LocalhostDownloadSupport.groovy | 4 +-
.../geb/support/delegate/BrowserDelegate.groovy | 2 +-
.../geb/support/delegate/PageDelegate.groovy | 2 +-
12 files changed, 251 insertions(+), 236 deletions(-)
diff --git a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/ContainerFileDetector.groovy b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/ContainerFileDetector.groovy
index 0b824738..f271c209 100644
--- a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/ContainerFileDetector.groovy
+++ b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/ContainerFileDetector.groovy
@@ -23,7 +23,7 @@ import org.openqa.selenium.remote.FileDetector
/**
* An extension of {@link org.openqa.selenium.remote.FileDetector}
- * that will get passed additional parameters from the webdriver container holder.
+ * that will get passed additional parameters from the webdriver container holder.
* <p>
* Implementations must provide a zero-argument constructor to ensure compatibility
* with {@link java.util.ServiceLoader}.
diff --git a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/ContainerGebTestDescription.groovy b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/ContainerGebTestDescription.groovy
index 65bb5f15..71251bcd 100644
--- a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/ContainerGebTestDescription.groovy
+++ b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/ContainerGebTestDescription.groovy
@@ -39,8 +39,8 @@ class ContainerGebTestDescription implements TestDescription {
testId = [
testInfo.feature.spec.displayName,
testInfo.feature.displayName,
- testInfo.displayName != testInfo.feature.displayName ? testInfo.displayName : null,
- testInfo.displayName != testInfo.feature.displayName ? testInfo.iterationIndex : null
+ testInfo.displayName == testInfo.feature.displayName ? null : testInfo.displayName,
+ testInfo.displayName == testInfo.feature.displayName ? null : testInfo.iterationIndex
].findAll(/* Remove nulls */).join(' ')
def safeName = testId.replaceAll('\\W+', '_')
diff --git a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/DefaultContainerFileDetector.groovy b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/DefaultContainerFileDetector.groovy
index a15a7e4c..c4472a36 100644
--- a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/DefaultContainerFileDetector.groovy
+++ b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/DefaultContainerFileDetector.groovy
@@ -23,7 +23,7 @@ import org.openqa.selenium.remote.UselessFileDetector
/**
* Detects files on the local disk.
- *
+ *
* @since 4.2
*/
class DefaultContainerFileDetector extends LocalFileDetector implements ContainerFileDetector {
@@ -31,7 +31,7 @@ class DefaultContainerFileDetector extends LocalFileDetector implements Containe
/**
* A file detector that never finds anything.
- *
+ *
* @since 4.2
*/
class UselessContainerFileDetector extends UselessFileDetector implements ContainerFileDetector {
diff --git a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/GrailsContainerGebExtension.groovy b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/GrailsContainerGebExtension.groovy
index b976aebd..28584375 100644
--- a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/GrailsContainerGebExtension.groovy
+++ b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/GrailsContainerGebExtension.groovy
@@ -70,7 +70,7 @@ class GrailsContainerGebExtension implements IGlobalExtension {
@Override
void visitSpec(SpecInfo spec) {
- if (isContainerGebSpec(spec) ) {
+ if (isContainerGebSpec(spec)) {
// Do not allow parallel execution since there's only 1 set of containers in testcontainers
spec.addExclusiveResource(exclusiveResource)
@@ -122,6 +122,13 @@ class GrailsContainerGebExtension implements IGlobalExtension {
}
}
+ private static void addGebExtensionOnFailureReporter(SpecInfo spec) {
+ List<MethodInfo> methods = spec.allFeatures*.featureMethod + spec.allFixtureMethods.toList()
+ methods.each {
+ it.addInterceptor(new GebOnFailureReporter())
+ }
+ }
+
@TailRecursive
private boolean isContainerGebSpec(SpecInfo spec) {
if (spec) {
@@ -132,14 +139,5 @@ class GrailsContainerGebExtension implements IGlobalExtension {
}
return false
}
-
-
-
- private static void addGebExtensionOnFailureReporter(SpecInfo spec) {
- List<MethodInfo> methods = spec.allFeatures*.featureMethod + spec.allFixtureMethods.toList()
- methods.each {
- it.addInterceptor(new GebOnFailureReporter())
- }
- }
}
diff --git a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/GrailsGebSettings.groovy b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/GrailsGebSettings.groovy
index 55b6bd2e..5326866c 100644
--- a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/GrailsGebSettings.groovy
+++ b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/GrailsGebSettings.groovy
@@ -89,12 +89,32 @@ class GrailsGebSettings {
this.startTime = startTime
}
+ boolean isRecordingEnabled() {
+ recordingMode != VncRecordingMode.SKIP
+ }
+
+ @Memoized
+ File getRecordingDirectory() {
+ if (!recordingEnabled) {
+ return null
+ }
+ createDirectory(recordingDirectoryName, 'recording')
+ }
+
+ @Memoized
+ File getReportingDirectory() {
+ if (!reportingDirectoryName) {
+ return null
+ }
+ createDirectory(reportingDirectoryName, 'reporting')
+ }
+
private static boolean getBooleanProperty(String propertyName, boolean defaultValue) {
Boolean.parseBoolean(System.getProperty(propertyName, defaultValue.toString()))
}
private static int getIntProperty(String propertyName, int defaultValue) {
- Integer.getInteger(propertyName, defaultValue) ?: defaultValue
+ System.getProperty(propertyName)?.toInteger() ?: defaultValue
}
private static Number getNumberProperty(String propertyName, Number defaultValue) {
@@ -103,9 +123,8 @@ class GrailsGebSettings {
try {
if (propValue.contains('.')) {
return new BigDecimal(propValue)
- } else {
- return Integer.parseInt(propValue)
}
+ return Integer.parseInt(propValue)
} catch (NumberFormatException ignored) {
log.warn(
'Could not parse property [{}] with value [{}] as a Number. Using default value [{}] instead.',
@@ -118,26 +137,6 @@ class GrailsGebSettings {
return defaultValue
}
- boolean isRecordingEnabled() {
- recordingMode != VncRecordingMode.SKIP
- }
-
- @Memoized
- File getRecordingDirectory() {
- if (!recordingEnabled) {
- return null
- }
- createDirectory(recordingDirectoryName, 'recording')
- }
-
- @Memoized
- File getReportingDirectory() {
- if (!reportingDirectoryName) {
- return null
- }
- createDirectory(reportingDirectoryName, 'reporting')
- }
-
private File createDirectory(String directoryName, String useCase) {
def dir = new File(
"$directoryName$File.separator${DateTimeFormatter.ofPattern('yyyyMMdd_HHmmss').format(startTime)}"
diff --git a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/WebDriverContainerHolder.groovy b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/WebDriverContainerHolder.groovy
index 9beaa695..bab7e1d4 100644
--- a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/WebDriverContainerHolder.groovy
+++ b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/WebDriverContainerHolder.groovy
@@ -18,7 +18,6 @@
*/
package grails.plugin.geb
-
import org.openqa.selenium.firefox.FirefoxOptions
import java.time.Duration
@@ -76,6 +75,8 @@ class WebDriverContainerHolder {
private static final String DEFAULT_HOSTNAME_FROM_HOST = 'localhost'
private static final String REMOTE_ADDRESS_PROPERTY = 'webdriver.remote.server'
+ private static final String HOST_PORT_PROPERTY = 'hostPort'
+ private static final String BASE_URL_PROPERTY = 'baseUrl'
private static final String DEFAULT_BROWSER = 'firefox'
GrailsGebSettings settings
@@ -102,85 +103,13 @@ class WebDriverContainerHolder {
boolean matchesCurrentContainerConfiguration(WebDriverContainerConfiguration specConf) {
specConf == containerConf &&
- settings.recordingMode == BrowserWebDriverContainer.VncRecordingMode.SKIP
- }
-
- /**
- * Returns a host port to use for the container in this order:
- * Class field 'hostPort' if found in the invocation (Spec).
- * A 'hostPort' property in the GebConfig configuration.
- * @param methodInvocation
- * @return
- */
- private static int findServerPort(IMethodInvocation methodInvocation) {
- // use the test class hostPort if specified
- try {
- return (int) methodInvocation.instance.metaClass.getProperty(
- methodInvocation.instance,
- 'hostPort'
- )
- } catch (ignored) {
- // Grails throws an IllegalStateException about their annotation here. We do not.
- log.info("no hostPort from methodInvocation")
- }
-
- try {
- // use geb config setting or default 8080
- Configuration gebConfig = new ConfigurationLoader().conf
- return (int) gebConfig.rawConfig.getProperty('hostPort')
- } catch (ignored) {
- log.info("no hostPort in config")
- }
-
- log.info("using default hostPort 8080")
- return 8080
- }
-
- /**
- * Returns a baseUrl from a setting if found in this order:
- * A class field 'baseUrl' if found in the invocation (Spec).
- * A 'baseUrl' property in the GebConfig configuration.
- * Or an empty String if not found.
- * @param methodInvocation
- * @return
- */
- private static String findBaseUrl(IMethodInvocation methodInvocation) {
- // use the test class baseUrl if specified
- try {
- String baseUrl = methodInvocation.instance.metaClass.getProperty(
- methodInvocation.instance,
- 'baseUrl'
- )
- if (baseUrl) {
- log.info("using baseUrl: ${baseUrl} from method invocation.")
- return baseUrl
- }
- } catch (ignored) {
- log.info("no baseUrl from methodInvocation")
- }
-
- try {
- // use geb config setting or default
- Configuration gebConfig = new ConfigurationLoader().conf
- String baseUrl = gebConfig.getProperty('baseUrl') ?: ""
- if (baseUrl != "") {
- log.info("using baseUrl: ${baseUrl} from configuration.")
- return baseUrl
- }
- } catch (ignored) {
- log.info("no baseUrl in config.")
- }
-
- log.info("no configured baseUrl found.")
- return ""
-
+ settings.recordingMode == BrowserWebDriverContainer.VncRecordingMode.SKIP
}
-
@PackageScope
boolean reinitialize(IMethodInvocation methodInvocation) {
def specConf = new WebDriverContainerConfiguration(
- methodInvocation.spec
+ methodInvocation.spec
)
if (matchesCurrentContainerConfiguration(specConf)) {
return false
@@ -200,25 +129,25 @@ class WebDriverContainerHolder {
validateDriverConf(gebConf)
if (customBrowser) {
log.info(
- 'A \'containerBrowser\' property was found in GebConfig. ' +
- "Using [$customBrowser] container image."
+ 'A \'containerBrowser\' property was found in GebConfig. ' +
+ "Using [$customBrowser] container image."
)
// Prepare for creating a container matching
// the GebConfig `containerBrowser` property.
dockerImageName = createDockerImageName(customBrowser)
} else {
log.info(
- 'No \'containerBrowser\' property found in GebConfig. ' +
- "Using default [$DEFAULT_BROWSER] container image."
+ 'No \'containerBrowser\' property found in GebConfig. ' +
+ "Using default [$DEFAULT_BROWSER] container image."
)
}
}
containerConf = specConf
container = new BrowserWebDriverContainer(dockerImageName).withRecordingMode(
- settings.recordingMode,
- settings.recordingDirectory,
- settings.recordingFormat
+ settings.recordingMode,
+ settings.recordingDirectory,
+ settings.recordingFormat
)
container.with {
@@ -230,11 +159,10 @@ class WebDriverContainerHolder {
startContainer(container, dockerImageName, customBrowser)
-
if (hostnameChanged) {
container.execInContainer(
- '/bin/sh', '-c',
- "echo '$hostIp\t$containerConf.hostName' | sudo tee -a /etc/hosts"
+ '/bin/sh', '-c',
+ "echo '$hostIp\t$containerConf.hostName' | sudo tee -a /etc/hosts"
)
}
@@ -256,9 +184,9 @@ class WebDriverContainerHolder {
// the `RemoteWebDriver` will be instantiated using the `webdriver.remote.server`
// system property. We set that property to inform the driver of the container address.
gebConf.driverConf = ClosureDecorators.withSystemProperty(
- gebConf.driverConf as Closure,
- REMOTE_ADDRESS_PROPERTY,
- container.seleniumAddress
+ gebConf.driverConf as Closure,
+ REMOTE_ADDRESS_PROPERTY,
+ container.seleniumAddress
)
} else {
// If no driver was set in GebConfig, create a Firefox driver
@@ -284,6 +212,144 @@ class WebDriverContainerHolder {
return true
}
+ void setupBrowserUrl(IMethodInvocation methodInvocation) {
+ if (!browser) {
+ return
+ }
+
+ // use a configured baseUrl if found, otherwise use localhost and hostPort
+ def baseUrl = findBaseUrl(methodInvocation)
+ if (baseUrl != "") {
+ browser.baseUrl = baseUrl
+ } else {
+ int hostPort = findServerPort(methodInvocation)
+ Testcontainers.exposeHostPorts(hostPort)
+ browser.baseUrl = "$containerConf.protocol://$containerConf.hostName:$hostPort"
+ }
+ }
+
+ /**
+ * Returns the hostname that the server under test is available on from the host.
+ * <p>This is useful when using any of the {@code download*()} methods as they will
+ * connect from the host, and not from within the container.
+ *
+ * <p>Defaults to {@code localhost}. If the value returned by {@code webDriverContainer.getHost()}
+ * is different from the default, this method will return the same value same as
+ * {@code webDriverContainer.getHost()}.
+ *
+ * @return the hostname for accessing the server under test from the host
+ */
+ String getHostNameFromHost() {
+ hostNameChanged ? container.host : DEFAULT_HOSTNAME_FROM_HOST
+ }
+
+ /**
+ * Workaround for https://github.com/testcontainers/testcontainers-java/issues/3998
+ * <p>
+ * Restarts the VNC recording container to enable separate recording files for each
+ * test method. This method uses reflection to access the VNC recording container
+ * field in BrowserWebDriverContainer. Should be called BEFORE each test starts.
+ */
+ void restartVncRecordingContainer() {
+ if (!settings.recordingEnabled || !settings.restartRecordingContainerPerTest || !container) {
+ return
+ }
+ try {
+ // Use reflection to access the VNC recording container field
+ def field = BrowserWebDriverContainer.getDeclaredField('vncRecordingContainer').tap {
+ accessible = true
+ }
+
+ def vncContainer = field.get(container) as VncRecordingContainer
+ if (vncContainer) {
+ // Stop the current VNC recording container
+ vncContainer.stop()
+ // Create and start a new VNC recording container for the next test
+ def newVncContainer = new VncRecordingContainer(container)
+ .withVncPassword('secret')
+ .withVncPort(5900)
+ .withVideoFormat(settings.recordingFormat)
+ field.set(container, newVncContainer)
+ newVncContainer.start()
+
+ log.debug('Successfully restarted VNC recording container')
+ }
+ } catch (Exception e) {
+ log.warn("Failed to restart VNC recording container: $e.message", e)
+ // Don't throw the exception to avoid breaking the test execution
+ }
+ }
+
+ /**
+ * Returns a host port to use for the container in this order:
+ * Class field 'hostPort' if found in the invocation (Spec).
+ * A 'hostPort' property in the GebConfig configuration.
+ * @param methodInvocation The method invocation.
+ * @return int The server port.
+ */
+ private static int findServerPort(IMethodInvocation methodInvocation) {
+ // use the test class hostPort if specified
+ try {
+ return (int) methodInvocation.instance.metaClass.getProperty(
+ methodInvocation.instance,
+ HOST_PORT_PROPERTY
+ )
+ } catch (ignored) {
+ // Grails throws an IllegalStateException about their annotation here. We do not.
+ log.info("no ${HOST_PORT_PROPERTY} from methodInvocation")
+ }
+
+ try {
+ // use geb config setting or default 8080
+ Configuration gebConfig = new ConfigurationLoader().conf
+ return (int) gebConfig.rawConfig.getProperty(HOST_PORT_PROPERTY)
+ } catch (ignored) {
+ log.info("no ${HOST_PORT_PROPERTY} in config")
+ }
+
+ log.info("using default ${HOST_PORT_PROPERTY} 8080")
+ return 8080
+ }
+
+ /**
+ * Returns a baseUrl from a setting if found in this order:
+ * A class field 'baseUrl' if found in the invocation (Spec).
+ * A 'baseUrl' property in the GebConfig configuration.
+ * Or an empty String if not found.
+ * @param methodInvocation The method invocation.
+ * @return String The base URL.
+ */
+ private static String findBaseUrl(IMethodInvocation methodInvocation) {
+ // use the test class baseUrl if specified
+ try {
+ String baseUrl = methodInvocation.instance.metaClass.getProperty(
+ methodInvocation.instance,
+ BASE_URL_PROPERTY
+ )
+ if (baseUrl) {
+ log.info("using ${BASE_URL_PROPERTY}: ${baseUrl} from method invocation.")
+ return baseUrl
+ }
+ } catch (ignored) {
+ log.info("no ${BASE_URL_PROPERTY} from methodInvocation")
+ }
+
+ try {
+ // use geb config setting or default
+ Configuration gebConfig = new ConfigurationLoader().conf
+ String baseUrl = gebConfig.getProperty(BASE_URL_PROPERTY) ?: ""
+ if (baseUrl != "") {
+ log.info("using ${BASE_URL_PROPERTY}: ${baseUrl} from configuration.")
+ return baseUrl
+ }
+ } catch (ignored) {
+ log.info("no ${BASE_URL_PROPERTY} in config.")
+ }
+
+ log.info("no configured ${BASE_URL_PROPERTY} found.")
+ return ""
+ }
+
private static Browser createBrowser(Configuration gebConf) {
def browser = new Browser(gebConf)
try {
@@ -313,18 +379,24 @@ class WebDriverContainerHolder {
private static void applyTimeouts(Browser browser, GrailsGebSettings settings) {
// Overwrite `GebConfig` timeouts with values explicitly set in
// `GrailsGebSettings` (via system properties)
- if (settings.implicitlyWait != DEFAULT_TIMEOUT_IMPLICITLY_WAIT)
+ if (settings.implicitlyWait != DEFAULT_TIMEOUT_IMPLICITLY_WAIT) {
browser.driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(settings.implicitlyWait))
- if (settings.pageLoadTimeout != DEFAULT_TIMEOUT_PAGE_LOAD)
+ }
+ if (settings.pageLoadTimeout != DEFAULT_TIMEOUT_PAGE_LOAD) {
browser.driver.manage().timeouts().pageLoadTimeout(Duration.ofSeconds(settings.pageLoadTimeout))
- if (settings.scriptTimeout != DEFAULT_TIMEOUT_SCRIPT)
+ }
+ if (settings.scriptTimeout != DEFAULT_TIMEOUT_SCRIPT) {
browser.driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(settings.scriptTimeout))
- if (settings.atCheckWaiting != DEFAULT_AT_CHECK_WAITING)
+ }
+ if (settings.atCheckWaiting != DEFAULT_AT_CHECK_WAITING) {
browser.config.atCheckWaiting = settings.atCheckWaiting
- if (settings.timeout != Wait.DEFAULT_TIMEOUT)
+ }
+ if (settings.timeout != Wait.DEFAULT_TIMEOUT) {
(browser.config.rawConfig.waiting as ConfigObject).timeout = settings.timeout
- if (settings.retryInterval != Wait.DEFAULT_RETRY_INTERVAL)
+ }
+ if (settings.retryInterval != Wait.DEFAULT_RETRY_INTERVAL) {
(browser.config.rawConfig.waiting as ConfigObject).retryInterval = settings.retryInterval
+ }
}
private static void startContainer(BrowserWebDriverContainer container, DockerImageName dockerImageName, String customBrowser) {
@@ -344,39 +416,6 @@ class WebDriverContainerHolder {
}
}
- void setupBrowserUrl(IMethodInvocation methodInvocation) {
- if (!browser) return
-
- // use a configured baseUrl if found, otherwise use localhost and hostPort
- def baseUrl = findBaseUrl(methodInvocation)
- if (baseUrl != "") {
- browser.baseUrl = baseUrl
- } else {
- int hostPort = findServerPort(methodInvocation)
- Testcontainers.exposeHostPorts(hostPort)
- browser.baseUrl = "$containerConf.protocol://$containerConf.hostName:$hostPort"
- }
-
- }
-
- private GebTestManager createTestManager() {
- new SpockGebTestManagerBuilder()
- .withReportingEnabled(containerConf.reporting)
- .withBrowserCreator(
- new Supplier<Browser>() {
- @Override
- Browser get() {
- browser
- }
- }
- )
- .build()
- }
-
- private boolean isHostnameChanged() {
- containerConf.hostName != ContainerGebConfiguration.DEFAULT_HOSTNAME_FROM_CONTAINER
- }
-
private static String getHostIp() {
try {
PortForwardingContainer.getDeclaredMethod('getNetwork').with {
@@ -393,25 +432,6 @@ class WebDriverContainerHolder {
}
}
- /**
- * Returns the hostname that the server under test is available on from the host.
- * <p>This is useful when using any of the {@code download*()} methods as they will
- * connect from the host, and not from within the container.
- *
- * <p>Defaults to {@code localhost}. If the value returned by {@code webDriverContainer.getHost()}
- * is different from the default, this method will return the same value same as
- * {@code webDriverContainer.getHost()}.
- *
- * @return the hostname for accessing the server under test from the host
- */
- String getHostNameFromHost() {
- hostNameChanged ? container.host : DEFAULT_HOSTNAME_FROM_HOST
- }
-
- private boolean isHostNameChanged() {
- container.host != ContainerGebConfiguration.DEFAULT_HOSTNAME_FROM_CONTAINER
- }
-
private static DockerImageName createDockerImageName(Object browserName) {
DockerImageName.parse(
"selenium/standalone-$browserName:$seleniumVersion"
@@ -431,6 +451,28 @@ class WebDriverContainerHolder {
SeleniumUtils.determineClasspathSeleniumVersion()
}
+ private GebTestManager createTestManager() {
+ new SpockGebTestManagerBuilder()
+ .withReportingEnabled(containerConf.reporting)
+ .withBrowserCreator(
+ new Supplier<Browser>() {
+ @Override
+ Browser get() {
+ browser
+ }
+ }
+ )
+ .build()
+ }
+
+ private boolean isHostnameChanged() {
+ containerConf.hostName != ContainerGebConfiguration.DEFAULT_HOSTNAME_FROM_CONTAINER
+ }
+
+ private boolean isHostNameChanged() {
+ container.host != ContainerGebConfiguration.DEFAULT_HOSTNAME_FROM_CONTAINER
+ }
+
@CompileStatic
@EqualsAndHashCode
private static class WebDriverContainerConfiguration {
@@ -460,43 +502,6 @@ class WebDriverContainerHolder {
}
}
- /**
- * Workaround for https://github.com/testcontainers/testcontainers-java/issues/3998
- * <p>
- * Restarts the VNC recording container to enable separate recording files for each
- * test method. This method uses reflection to access the VNC recording container
- * field in BrowserWebDriverContainer. Should be called BEFORE each test starts.
- */
- void restartVncRecordingContainer() {
- if (!settings.recordingEnabled || !settings.restartRecordingContainerPerTest || !container) {
- return
- }
- try {
- // Use reflection to access the VNC recording container field
- def field = BrowserWebDriverContainer.getDeclaredField('vncRecordingContainer').tap {
- accessible = true
- }
-
- def vncContainer = field.get(container) as VncRecordingContainer
- if (vncContainer) {
- // Stop the current VNC recording container
- vncContainer.stop()
- // Create and start a new VNC recording container for the next test
- def newVncContainer = new VncRecordingContainer(container)
- .withVncPassword('secret')
- .withVncPort(5900)
- .withVideoFormat(settings.recordingFormat)
- field.set(container, newVncContainer)
- newVncContainer.start()
-
- log.debug('Successfully restarted VNC recording container')
- }
- } catch (Exception e) {
- log.warn("Failed to restart VNC recording container: $e.message", e)
- // Don't throw the exception to avoid breaking the test execution
- }
- }
-
@CompileStatic
private static class ClosureDecorators {
@@ -521,7 +526,7 @@ class WebDriverContainerHolder {
private static class SysPropScope {
private static final ThreadLocal<Map<String,String>> OVERRIDDEN_SYSTEM_PROPERTIES =
- ThreadLocal.withInitial { [:] as Map<String,String> }
+ ThreadLocal.withInitial { [:] } as ThreadLocal<Map<String, String>>
@Lazy // Thread-safe wrapping of system properties
private static Properties propertiesWrappedOnFirstAccess = {
@@ -538,8 +543,14 @@ class WebDriverContainerHolder {
try {
return body.call()
} finally {
- if (prev == null) map.remove(key) else map[key] = prev
- if (map.isEmpty()) OVERRIDDEN_SYSTEM_PROPERTIES.remove()
+ if (prev == null) {
+ map.remove(key)
+ } else {
+ map[key] = prev
+ }
+ if (map.isEmpty()) {
+ OVERRIDDEN_SYSTEM_PROPERTIES.remove()
+ }
}
}
@@ -554,8 +565,4 @@ class WebDriverContainerHolder {
}
}
-
-
-
-
}
diff --git a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/serviceloader/ServiceRegistry.groovy b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/serviceloader/ServiceRegistry.groovy
index 7b18c118..0d2b15a6 100644
--- a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/serviceloader/ServiceRegistry.groovy
+++ b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/serviceloader/ServiceRegistry.groovy
@@ -42,8 +42,8 @@ import groovy.transform.CompileStatic
class ServiceRegistry {
private static final ThreadLocal<HashMap<Class<?>, Object>> INSTANCES = ThreadLocal.withInitial {
- new HashMap<Class<?>, Object>()
- }
+ [:]
+ } as ThreadLocal<HashMap<Class<?>, Object>>
/**
* Returns the service instance of the given service type, loading it using
diff --git a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/BrowserType.groovy b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/BrowserType.groovy
index 4ebefd32..b6ec9c49 100644
--- a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/BrowserType.groovy
+++ b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/BrowserType.groovy
@@ -19,12 +19,24 @@
package grails.plugin.geb.support
/**
+ * Represents the supported browser types.
*
+ * <p>This enum defines the available browser options that can be used.</p>
*/
enum BrowserType {
+ /**
+ * Google Chrome browser.
+ */
+
CHROME,
+ /**
+ * Mozilla Firefox browser.
+ */
FIREFOX,
- EDGE
+ /**
+ * Microsoft Edge browser.
+ */
+ EDGE
}
\ No newline at end of file
diff --git a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/ContainerGebFileInputSource.groovy b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/ContainerGebFileInputSource.groovy
index 5ec39d57..23c11650 100644
--- a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/ContainerGebFileInputSource.groovy
+++ b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/ContainerGebFileInputSource.groovy
@@ -16,7 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-
package grails.plugin.geb.support
/**
diff --git a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/LocalhostDownloadSupport.groovy b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/LocalhostDownloadSupport.groovy
index 8f782c97..f2167fc9 100644
--- a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/LocalhostDownloadSupport.groovy
+++ b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/LocalhostDownloadSupport.groovy
@@ -31,7 +31,7 @@ import java.util.regex.Pattern
@CompileStatic
class LocalhostDownloadSupport extends DefaultDownloadSupport {
- private final static Pattern urlPattern = ~/(https?:\/\/)([^\/:]+)(:\d+\/.*)/
+ private final static Pattern URL_PATTERN = ~/(https?:\/\/)([^\/:]+)(:\d+\/.*)/
private final String hostNameFromHost
private final Browser browser
@@ -48,7 +48,7 @@ class LocalhostDownloadSupport extends DefaultDownloadSupport {
}
private String resolveBase(Map options) {
- return options.base ?: browser.driver.currentUrl.replaceAll(urlPattern) { match, proto, host, rest ->
+ return options.base ?: browser.driver.currentUrl.replaceAll(URL_PATTERN) { match, proto, host, rest ->
"${proto}${hostNameFromHost}${rest}"
}
}
diff --git a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/delegate/BrowserDelegate.groovy b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/delegate/BrowserDelegate.groovy
index 0ad9763a..4809047c 100644
--- a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/delegate/BrowserDelegate.groovy
+++ b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/delegate/BrowserDelegate.groovy
@@ -386,7 +386,7 @@ trait BrowserDelegate {
* Delegates to {@link geb.Browser#setNetworkLatency(Duration)}.
*/
void setNetworkLatency(Duration duration) {
- browser.setNetworkLatency(duration)
+ browser.networkLatency = duration
}
/**
diff --git a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/delegate/PageDelegate.groovy b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/delegate/PageDelegate.groovy
index 1706abe5..cbd5f259 100644
--- a/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/delegate/PageDelegate.groovy
+++ b/integration/geb-testcontainers/src/main/groovy/grails/plugin/geb/support/delegate/PageDelegate.groovy
@@ -409,7 +409,7 @@ trait PageDelegate implements Navigable, AlertAndConfirmSupport, WaitingSupport,
}
@Override
- void interact(@DelegatesTo(strategy = 1, value = InteractDelegate.class) Closure interactionClosure) {
+ void interact(@DelegatesTo(strategy = 1, value = InteractDelegate) Closure interactionClosure) {
page.interact(interactionClosure)
}
}
\ No newline at end of file