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 <[email protected]> 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
