JonasPammer commented on code in PR #15067: URL: https://github.com/apache/grails-core/pull/15067#discussion_r2356688532
########## grails-geb/src/testFixtures/groovy/grails/plugin/geb/WebDriverContainerHolder.groovy: ########## @@ -59,99 +64,130 @@ import grails.plugin.geb.serviceloader.ServiceRegistry 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[] SELENIUM_BROWSERS = ['chrome', 'edge', 'firefox'] + private static final String DEFAULT_DOCKER_IMAGE_NAME = 'selenium/standalone-chrome' - GrailsGebSettings grailsGebSettings + GrailsGebSettings settings GebTestManager testManager - Browser currentBrowser - BrowserWebDriverContainer currentContainer - WebDriverContainerConfiguration currentConfiguration + Browser browser + BrowserWebDriverContainer container + WebDriverContainerConfiguration containerConf - WebDriverContainerHolder(GrailsGebSettings grailsGebSettings) { - this.grailsGebSettings = grailsGebSettings + WebDriverContainerHolder(GrailsGebSettings settings) { + this.settings = settings } boolean isInitialized() { - currentContainer != null + container != null } void stop() { - currentContainer?.stop() - currentContainer = null - currentBrowser = null + container?.stop() + container = null + browser = null testManager = null - currentConfiguration = null + containerConf = null } - boolean matchesCurrentContainerConfiguration(WebDriverContainerConfiguration specConfiguration) { - specConfiguration == currentConfiguration && grailsGebSettings.recordingMode == BrowserWebDriverContainer.VncRecordingMode.SKIP + boolean matchesCurrentContainerConfiguration(WebDriverContainerConfiguration specConf) { + specConf == containerConf && + settings.recordingMode == BrowserWebDriverContainer.VncRecordingMode.SKIP } - private static int getPort(IMethodInvocation invocation) { + private static int findServerPort(IMethodInvocation methodInvocation) { try { - return (int) invocation.instance.metaClass.getProperty(invocation.instance, 'serverPort') + return (int) methodInvocation.instance.metaClass.getProperty( + methodInvocation.instance, + 'serverPort' + ) } catch (ignored) { - throw new IllegalStateException('Test class must be annotated with @Integration for serverPort to be injected') + throw new IllegalStateException( + 'Test class must be annotated with @Integration for serverPort to be injected' + ) } } @PackageScope - boolean reinitialize(IMethodInvocation invocation) { - WebDriverContainerConfiguration specConfiguration = new WebDriverContainerConfiguration( - invocation.getSpec() + boolean reinitialize(IMethodInvocation methodInvocation) { + def specConf = new WebDriverContainerConfiguration( + methodInvocation.spec ) - if (matchesCurrentContainerConfiguration(specConfiguration)) { + if (matchesCurrentContainerConfiguration(specConf)) { return false } if (initialized) { stop() } - currentConfiguration = specConfiguration - currentContainer = new BrowserWebDriverContainer().withRecordingMode( - grailsGebSettings.recordingMode, - grailsGebSettings.recordingDirectory, - grailsGebSettings.recordingFormat + def gebConf = new ConfigurationLoader().conf + def dockerImageName = defaultDockerImageName + + def gebConfigFileFound = false + if (gebConfigFileExists) { + if (!gebConf.driverConf instanceof Closure) { + throw new IllegalStateException( + 'The "driver" config value must be a Closure that returns an instance of RemoteWebDriver.' + ) + } + gebConfigFileFound = true + + // Prepare for creating a suitable container matching the driver + // configured in GebConfig.groovy, or more specifically, + // specified by the `configuredBrowser` property. + dockerImageName = createDockerImageName(gebConf.rawConfig.configuredBrowser) Review Comment: regression for GebConfig's that don't have this special var - add a default here? we already imply Chrome at `new RemoteWebDriver(container.seleniumAddress, new ChromeOptions()` when no GebConfig existed on classpath ########## grails-geb/README.md: ########## @@ -161,6 +161,28 @@ To enable tracing, set the following system property: This allows you to opt in to tracing when an OpenTelemetry collector is available. +#### GebConfig.groovy and using non-default browser settings +Provide a `GebConfig.groovy` on the test runtime classpath (commonly `src/integration-test/resources`, but any location on the test classpath works) to customize the browser. + +To make this work, ensure: +1. The `driver` property in your `GebConfig` is a `Closure` that returns a `RemoteWebDriver` instance. +2. You set a custom `configuredBrowser` property so that `ContainerGebSpec` can start a matching container (e.g. "chrome", "firefox", "edge"). Review Comment: as pointed out some projects potentially have GebConfig next to ContainerGebConfig. I saw other extensions always prefix their variables with their extension (e.g. sauceLabsBrowser), maybe we should too to avoid confusion? e.g. `containerBrowser` (in reference to containergebspec) ########## grails-geb/src/testFixtures/groovy/grails/plugin/geb/WebDriverContainerHolder.groovy: ########## @@ -245,19 +268,47 @@ 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>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()}. + * 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() { - return hostNameChanged ? currentContainer.host : DEFAULT_HOSTNAME_FROM_HOST + hostNameChanged ? container.host : DEFAULT_HOSTNAME_FROM_HOST } private boolean isHostNameChanged() { - return currentContainer.host != ContainerGebConfiguration.DEFAULT_HOSTNAME_FROM_CONTAINER + container.host != ContainerGebConfiguration.DEFAULT_HOSTNAME_FROM_CONTAINER + } + + private static DockerImageName getDefaultDockerImageName() { + DockerImageName.parse("$DEFAULT_DOCKER_IMAGE_NAME:$seleniumVersion") + } + + private static DockerImageName createDockerImageName(Object configuredBrowser) { + validateConfiguredBrowser(configuredBrowser) + DockerImageName.parse("selenium/standalone-$configuredBrowser:$seleniumVersion") + } + + private static void validateConfiguredBrowser(Object browser) { Review Comment: why only allow a hardcoded subset? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@grails.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org