diff --git a/README.md b/README.md index 897c0b6..6e88b85 100644 --- a/README.md +++ b/README.md @@ -53,9 +53,21 @@ This requires a [compatible container runtime](https://java.testcontainers.org/s If you choose to use the `ContainerGebSpec` class, as long as you have a compatible container runtime installed, you don't need to do anything else. Just run `./gradlew integrationTest` and a container will be started and configured to start a browser that can access your application under test. +#### Parallel Execution + +Parallel execution of `ContainerGebSpec` specifications is not currently supported. + #### Custom Host Configuration -The annotation `ContainerGebConfiguration` exists to customize the connection the container will use to access the application under test. The annotation is not required and `ContainerGebSpec` will use the default values in this annotation if it's not present. +The annotation `ContainerGebConfiguration` exists to customize the connection the container will use to access the application under test. The annotation is not required and `ContainerGebSpec` will use the default values in this annotation if it's not present. A traditional `GebConfig.groovy` can be provided to configure non-container specific settings. + +#### Reporting + +To configure reporting, enable it using the `recording` property on the annotation `ContainerGebConfiguration`. The following system properties exist for reporting configuration: + +* `grails.geb.reporting.directory` + * purpose: if the test enables reporting, the directory to save the reports relative to the project directory + * defaults to `build/gebContainer/reports` #### Recording @@ -74,7 +86,7 @@ By default, no test recording will be performed. Various system properties exis * `grails.geb.recording.directory` * purpose: the directory to save the recordings relative to the project directory - * defaults to `build/recordings` + * defaults to `build/gebContainer/recordings` * `grails.geb.recording.format` diff --git a/gradle.properties b/gradle.properties index b82b693..748654e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ projectVersion=5.0.0-SNAPSHOT grailsVersion=7.0.0-SNAPSHOT grailsGradlePluginVersion=7.0.0-SNAPSHOT seleniumVersion=4.25.0 -testcontainersVersion=1.20.2 +testcontainersVersion=1.20.4 # This prevents the Grails Gradle Plugin from unnecessarily excluding slf4j-simple in the generated POMs # https://github.com/grails/grails-gradle-plugin/issues/222 diff --git a/spock-container-test-app/src/integration-test/groovy/org/demo/spock/RootPageSpec.groovy b/spock-container-test-app/src/integration-test/groovy/org/demo/spock/RootPageSpec.groovy index 2ef4364..3156dfd 100644 --- a/spock-container-test-app/src/integration-test/groovy/org/demo/spock/RootPageSpec.groovy +++ b/spock-container-test-app/src/integration-test/groovy/org/demo/spock/RootPageSpec.groovy @@ -1,5 +1,10 @@ package org.demo.spock +import geb.report.CompositeReporter +import geb.report.PageSourceReporter +import geb.report.Reporter +import geb.report.ScreenshotReporter +import grails.plugin.geb.ContainerGebConfiguration import grails.plugin.geb.ContainerGebSpec import grails.testing.mixin.integration.Integration @@ -8,13 +13,21 @@ import grails.testing.mixin.integration.Integration * for more instructions on how to write functional tests with Grails and Geb. */ @Integration +@ContainerGebConfiguration(reporting = true) class RootPageSpec extends ContainerGebSpec { + @Override + Reporter createReporter() { + // Override the default reporter to demonstrate how this can be customized + new CompositeReporter(new ScreenshotReporter(), new PageSourceReporter()) + } + void 'should display the correct title on the home page'() { when: 'visiting the home page' go '/' then: 'the page title is correct' + report('root page report') title == 'Welcome to Grails' } } diff --git a/src/testFixtures/groovy/grails/plugin/geb/ContainerAwareDownloadSupport.groovy b/src/testFixtures/groovy/grails/plugin/geb/ContainerAwareDownloadSupport.groovy index 407ddbe..26b59c6 100644 --- a/src/testFixtures/groovy/grails/plugin/geb/ContainerAwareDownloadSupport.groovy +++ b/src/testFixtures/groovy/grails/plugin/geb/ContainerAwareDownloadSupport.groovy @@ -15,13 +15,10 @@ */ package grails.plugin.geb -import geb.Browser -import geb.download.DefaultDownloadSupport import geb.download.DownloadSupport import groovy.transform.CompileStatic import groovy.transform.SelfType - -import java.util.regex.Pattern +import spock.lang.Shared /** * A custom implementation of {@link geb.download.DownloadSupport} for enabling the use of its {@code download*()} methods @@ -35,41 +32,13 @@ import java.util.regex.Pattern * setups, ensuring the host network context is used for download requests.
* * @author Mattias Reichel - * @since 5.0 + * @since 4.1 */ @CompileStatic @SelfType(ContainerGebSpec) trait ContainerAwareDownloadSupport implements DownloadSupport { @Delegate - private final DownloadSupport downloadSupport = new LocalhostDownloadSupport(browser, this) - - abstract Browser getBrowser() - - abstract String getHostNameFromHost() - - private static class LocalhostDownloadSupport extends DefaultDownloadSupport { - - private final static Pattern urlPattern = ~/(https?:\/\/)([^\/:]+)(:\d+\/.*)/ - - private final ContainerAwareDownloadSupport parent - private final Browser browser - - LocalhostDownloadSupport(Browser browser, ContainerAwareDownloadSupport parent) { - super(browser) - this.browser = browser - this.parent = parent - } - - @Override - HttpURLConnection download(Map options) { - return super.download([*: options, base: resolveBase(options)]) - } - - private String resolveBase(Map options) { - return options.base ?: browser.driver.currentUrl.replaceAll(urlPattern) { match, proto, host, rest -> - "${proto}${parent.hostNameFromHost}${rest}" - } - } - } + @Shared + static DownloadSupport downloadSupport } \ No newline at end of file diff --git a/src/testFixtures/groovy/grails/plugin/geb/ContainerGebConfiguration.groovy b/src/testFixtures/groovy/grails/plugin/geb/ContainerGebConfiguration.groovy index 83577e6..a24ce27 100644 --- a/src/testFixtures/groovy/grails/plugin/geb/ContainerGebConfiguration.groovy +++ b/src/testFixtures/groovy/grails/plugin/geb/ContainerGebConfiguration.groovy @@ -15,6 +15,8 @@ */ package grails.plugin.geb +import org.testcontainers.containers.GenericContainer + import java.lang.annotation.ElementType import java.lang.annotation.Retention import java.lang.annotation.RetentionPolicy @@ -24,13 +26,13 @@ import java.lang.annotation.Target * Can be used to configure the protocol and hostname that the container's browser will use * * @author James Daugherty - * @since 5.0 + * @since 4.1 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface ContainerGebConfiguration { - static final String DEFAULT_HOSTNAME_FROM_CONTAINER = 'host.testcontainers.internal' + static final String DEFAULT_HOSTNAME_FROM_CONTAINER = GenericContainer.INTERNAL_HOST_HOSTNAME static final String DEFAULT_PROTOCOL = 'http' /** @@ -45,4 +47,9 @@ import java.lang.annotation.Target *This is useful when the server under test needs to be accessed with a certain hostname. */ String hostName() default DEFAULT_HOSTNAME_FROM_CONTAINER + + /** + * Whether reporting should be enabled for this test. Add a `GebConfig.groovy` to customize the reporter configuration. + */ + boolean reporting() default false } \ No newline at end of file diff --git a/src/testFixtures/groovy/grails/plugin/geb/ContainerGebRecordingExtension.groovy b/src/testFixtures/groovy/grails/plugin/geb/ContainerGebRecordingExtension.groovy deleted file mode 100644 index 931c694..0000000 --- a/src/testFixtures/groovy/grails/plugin/geb/ContainerGebRecordingExtension.groovy +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2024 original author or authors - * - * 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 - * - * https://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 grails.plugin.geb - -import grails.testing.mixin.integration.Integration -import groovy.transform.CompileStatic -import groovy.transform.TailRecursive -import groovy.util.logging.Slf4j -import org.spockframework.runtime.extension.IGlobalExtension -import org.spockframework.runtime.model.SpecInfo - -import java.time.LocalDateTime - -/** - * A Spock Extension that manages the Testcontainers lifecycle for a {@link grails.plugin.geb.ContainerGebSpec} - * - * @author James Daugherty - * @since 5.0 - */ -@Slf4j -@CompileStatic -class ContainerGebRecordingExtension implements IGlobalExtension { - - WebDriverContainerHolder holder - - @Override - void start() { - holder = new WebDriverContainerHolder(new RecordingSettings()) - addShutdownHook { - holder.stop() - } - } - - @Override - void stop() { - holder.stop() - } - - @Override - void visitSpec(SpecInfo spec) { - if (isContainerGebSpec(spec) && validateContainerGebSpec(spec)) { - ContainerGebTestListener listener = new ContainerGebTestListener(holder, spec, LocalDateTime.now()) - spec.addSetupInterceptor { - holder.reinitialize(it) - (it.sharedInstance as ContainerGebSpec).webDriverContainer = holder.currentContainer - } - - spec.addListener(listener) - } - } - - @TailRecursive - private boolean isContainerGebSpec(SpecInfo spec) { - if (spec != null) { - if (spec.filename.startsWith('ContainerGebSpec.')) { - return true - } - return isContainerGebSpec(spec.superSpec) - } - return false - } - - private static boolean validateContainerGebSpec(SpecInfo specInfo) { - if (!specInfo.annotations.find { it.annotationType() == Integration }) { - throw new IllegalArgumentException('ContainerGebSpec classes must be annotated with @Integration') - } - - return true - } -} - diff --git a/src/testFixtures/groovy/grails/plugin/geb/ContainerGebSpec.groovy b/src/testFixtures/groovy/grails/plugin/geb/ContainerGebSpec.groovy index 0b3e8a0..94647f6 100644 --- a/src/testFixtures/groovy/grails/plugin/geb/ContainerGebSpec.groovy +++ b/src/testFixtures/groovy/grails/plugin/geb/ContainerGebSpec.groovy @@ -15,8 +15,10 @@ */ package grails.plugin.geb +import geb.report.CompositeReporter +import geb.report.PageSourceReporter +import geb.report.Reporter import geb.test.GebTestManager -import geb.test.ManagedGebTest import geb.transform.DynamicallyDispatchesToBrowser import org.testcontainers.containers.BrowserWebDriverContainer import spock.lang.Shared @@ -41,24 +43,15 @@ import spock.lang.Specification * @author Søren Berg Glasius * @author Mattias Reichel * @author James Daugherty - * @since 5.0 + * @since 4.1 */ @DynamicallyDispatchesToBrowser -abstract class ContainerGebSpec extends Specification implements ManagedGebTest, ContainerAwareDownloadSupport { - - private static final String DEFAULT_HOSTNAME_FROM_HOST = 'localhost' - boolean reportingEnabled = false - - @Override - @Delegate(includes = ['getBrowser', 'report']) - GebTestManager getTestManager() { - return isReportingEnabled() ? - GebTestManagerProvider.getReportingInstance() : - GebTestManagerProvider.getInstance() - } +abstract class ContainerGebSpec extends Specification implements ContainerAwareDownloadSupport { @Shared - BrowserWebDriverContainer webDriverContainer + @Delegate(includes = ['getBrowser', 'report']) + @SuppressWarnings('unused') + static GebTestManager testManager /** * Get access to container running the web-driver, for convenience to execInContainer, copyFileToContainer etc. @@ -68,25 +61,13 @@ abstract class ContainerGebSpec extends Specification implements ManagedGebTest, * @see org.testcontainers.containers.ContainerState#copyFileFromContainer(java.lang.String, java.lang.String) * @see org.testcontainers.containers.ContainerState */ - BrowserWebDriverContainer getContainer() { - return webDriverContainer - } + @Shared + static BrowserWebDriverContainer container /** - * Returns the hostname that the server under test is available on from the host. - *
This is useful when using any of the {@code download*()} methods as they will connect from the host, - * and not from within the container. - *
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 + * The reporter that Geb should use when reporting is enabled. */ - @Override - String getHostNameFromHost() { - return hostNameChanged ? webDriverContainer.host : DEFAULT_HOSTNAME_FROM_HOST - } - - private boolean isHostNameChanged() { - return webDriverContainer.host != ContainerGebConfiguration.DEFAULT_HOSTNAME_FROM_CONTAINER + Reporter createReporter() { + new CompositeReporter(new PageSourceReporter()) } } \ No newline at end of file diff --git a/src/testFixtures/groovy/grails/plugin/geb/ContainerGebTestDescription.groovy b/src/testFixtures/groovy/grails/plugin/geb/ContainerGebTestDescription.groovy index d1a5cc7..ab72c14 100644 --- a/src/testFixtures/groovy/grails/plugin/geb/ContainerGebTestDescription.groovy +++ b/src/testFixtures/groovy/grails/plugin/geb/ContainerGebTestDescription.groovy @@ -19,15 +19,11 @@ import groovy.transform.CompileStatic import org.spockframework.runtime.model.IterationInfo import org.testcontainers.lifecycle.TestDescription -import java.time.LocalDateTime -import java.time.format.DateTimeFormatter - /** * Implements {@link org.testcontainers.lifecycle.TestDescription} to customize recording names. * - * @see org.testcontainers.lifecycle.TestDescription * @author James Daugherty - * @since 5.0 + * @since 4.1 */ @CompileStatic class ContainerGebTestDescription implements TestDescription { @@ -35,9 +31,9 @@ class ContainerGebTestDescription implements TestDescription { String testId String filesystemFriendlyName - ContainerGebTestDescription(IterationInfo testInfo, LocalDateTime runDate) { + ContainerGebTestDescription(IterationInfo testInfo) { testId = testInfo.displayName String safeName = testId.replaceAll('\\W+', '_') - filesystemFriendlyName = "${DateTimeFormatter.ofPattern('yyyyMMdd_HHmmss').format(runDate)}_${safeName}" + filesystemFriendlyName = safeName } } diff --git a/src/testFixtures/groovy/grails/plugin/geb/GebOnFailureReporter.groovy b/src/testFixtures/groovy/grails/plugin/geb/GebOnFailureReporter.groovy new file mode 100644 index 0000000..9a18947 --- /dev/null +++ b/src/testFixtures/groovy/grails/plugin/geb/GebOnFailureReporter.groovy @@ -0,0 +1,46 @@ +/* + * Copyright 2016 the original author or authors. + * + * 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 grails.plugin.geb + +import groovy.transform.CompileStatic +import org.opentest4j.IncompleteExecutionException +import org.spockframework.runtime.extension.IMethodInterceptor +import org.spockframework.runtime.extension.IMethodInvocation + +/** + * This class is a direct clone of {@link geb.spock.OnFailureReporter OnFailureReporter}, except it works for the + * {@link grails.plugin.geb.ContainerGebSpec ContainerGebSpec}. + */ +@CompileStatic +class GebOnFailureReporter implements IMethodInterceptor { + void intercept(IMethodInvocation invocation) throws Throwable { + try { + invocation.proceed() + } catch (IncompleteExecutionException notACauseForReporting) { + throw notACauseForReporting + } catch (Throwable throwable) { + ContainerGebSpec spec = invocation.instance as ContainerGebSpec + if (spec.testManager.reportingEnabled) { + try { + spec.testManager.reportFailure() + } catch (ignored) { + //ignore + } + } + throw throwable + } + } +} diff --git a/src/testFixtures/groovy/grails/plugin/geb/ContainerGebTestListener.groovy b/src/testFixtures/groovy/grails/plugin/geb/GebRecordingTestListener.groovy similarity index 81% rename from src/testFixtures/groovy/grails/plugin/geb/ContainerGebTestListener.groovy rename to src/testFixtures/groovy/grails/plugin/geb/GebRecordingTestListener.groovy index 5da846a..a4bbf05 100644 --- a/src/testFixtures/groovy/grails/plugin/geb/ContainerGebTestListener.groovy +++ b/src/testFixtures/groovy/grails/plugin/geb/GebRecordingTestListener.groovy @@ -30,26 +30,22 @@ import java.time.LocalDateTime * @see org.testcontainers.containers.BrowserWebDriverContainer#afterTest * * @author James Daugherty - * @since 5.0 + * @since 4.1 */ @CompileStatic -class ContainerGebTestListener extends AbstractRunListener { +class GebRecordingTestListener extends AbstractRunListener { WebDriverContainerHolder containerHolder ErrorInfo errorInfo - SpecInfo spec - LocalDateTime runDate - ContainerGebTestListener(WebDriverContainerHolder containerHolder, SpecInfo spec, LocalDateTime runDate) { - this.spec = spec - this.runDate = runDate + GebRecordingTestListener(WebDriverContainerHolder containerHolder) { this.containerHolder = containerHolder } @Override void afterIteration(IterationInfo iteration) { containerHolder.currentContainer.afterTest( - new ContainerGebTestDescription(iteration, runDate), + new ContainerGebTestDescription(iteration), Optional.ofNullable(errorInfo?.exception) ) errorInfo = null diff --git a/src/testFixtures/groovy/grails/plugin/geb/GebTestManagerProvider.groovy b/src/testFixtures/groovy/grails/plugin/geb/GebTestManagerProvider.groovy deleted file mode 100644 index 454daa1..0000000 --- a/src/testFixtures/groovy/grails/plugin/geb/GebTestManagerProvider.groovy +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2024 original author or authors - * - * 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 - * - * https://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 grails.plugin.geb - -import geb.spock.SpockGebTestManagerBuilder -import geb.test.GebTestManager -import groovy.transform.CompileStatic - -/** - * A provider class for managing instances of {@link GebTestManager}. - * This class uses the Initialization-on-Demand Holder Idiom to ensure thread-safe, - * lazy initialization of {@link GebTestManager} instances for use in Geb tests. - * - *
The class provides two static instances:
- *This class cannot be instantiated, as it is designed to be used as a - * utility provider.
- * - * @see GebTestManager - * @see SpockGebTestManagerBuilder - * - * @author Mattias Reichel - * @author Søren Berg Glasius - * @since 5.0 - */ -@CompileStatic -class GebTestManagerProvider { - - /** - * A lazily and thread-safe-initialized instance of {@link GebTestManager}. - * Built using {@link SpockGebTestManagerBuilder}. - */ - @Lazy - static volatile GebTestManager instance = { - new SpockGebTestManagerBuilder().build() - }() - - /** - * A lazily and thread-safe-initialized instance of {@link GebTestManager} - * with reporting enabled. Built using {@link SpockGebTestManagerBuilder}. - */ - @Lazy - static volatile GebTestManager reportingInstance = { - new SpockGebTestManagerBuilder() - .withReportingEnabled(true) - .build() - }() - - /** - * Private constructor to prevent instantiation of this utility class. - */ - private GebTestManagerProvider() {} - -} \ No newline at end of file diff --git a/src/testFixtures/groovy/grails/plugin/geb/GrailsContainerGebExtension.groovy b/src/testFixtures/groovy/grails/plugin/geb/GrailsContainerGebExtension.groovy new file mode 100644 index 0000000..3a60fe1 --- /dev/null +++ b/src/testFixtures/groovy/grails/plugin/geb/GrailsContainerGebExtension.groovy @@ -0,0 +1,146 @@ +/* + * Copyright 2024 original author or authors + * + * 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 + * + * https://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 grails.plugin.geb + +import grails.testing.mixin.integration.Integration +import groovy.transform.CompileStatic +import groovy.transform.TailRecursive +import groovy.util.logging.Slf4j +import org.spockframework.runtime.extension.IGlobalExtension +import org.spockframework.runtime.model.MethodInfo +import org.spockframework.runtime.model.SpecInfo +import org.spockframework.runtime.model.parallel.ExclusiveResource +import org.spockframework.runtime.model.parallel.ResourceAccessMode + +import java.time.LocalDateTime + +/** + * A Spock Extension that manages the Testcontainers lifecycle for a {@link grails.plugin.geb.ContainerGebSpec} + * + * ContainerGebSpec cannot be a {@link geb.test.ManagedGebTest ManagedGebTest} because it would cause the test manager
+ * to be initialized out of sequence of the container management. Instead, we initialize the same interceptors
+ * as the {@link geb.spock.GebExtension GebExtension} does.
+ *
+ * @author James Daugherty
+ * @since 4.1
+ */
+@Slf4j
+@CompileStatic
+class GrailsContainerGebExtension implements IGlobalExtension {
+
+ ExclusiveResource exclusiveResource
+ WebDriverContainerHolder holder
+
+ @Override
+ void start() {
+ exclusiveResource = new ExclusiveResource(
+ ContainerGebSpec.name,
+ ResourceAccessMode.READ_WRITE
+ )
+ holder = new WebDriverContainerHolder(
+ new GrailsGebSettings(LocalDateTime.now())
+ )
+ addShutdownHook {
+ holder.stop()
+ }
+ }
+
+ @Override
+ void stop() {
+ holder.stop()
+ }
+
+ @Override
+ void visitSpec(SpecInfo spec) {
+ if (isContainerGebSpec(spec) && validateContainerGebSpec(spec)) {
+ // Do not allow parallel execution since there's only 1 set of containers in testcontainers
+ spec.addExclusiveResource(exclusiveResource)
+
+ // Always initialize the container requirements first so the GebTestManager can properly configure the browser
+ spec.addSharedInitializerInterceptor { invocation ->
+ holder.reinitialize(invocation)
+
+ ContainerGebSpec gebSpec = invocation.sharedInstance as ContainerGebSpec
+ gebSpec.container = holder.currentContainer
+ gebSpec.testManager = holder.testManager
+ gebSpec.downloadSupport = new LocalhostDownloadSupport(
+ holder.currentBrowser,
+ holder.hostNameFromHost
+ )
+
+ // code below here is from the geb.spock.GebExtension since there can only be 1 shared initializer per extension
+ holder.testManager.beforeTestClass(invocation.spec.reflection)
+ invocation.proceed()
+ }
+
+ spec.addSetupInterceptor {
+ // Grails will be initialized by this point, so setup the browser url correctly
+ holder.setupBrowserUrl(it)
+ }
+
+ spec.addInterceptor { invocation ->
+ try {
+ invocation.proceed()
+ } finally {
+ holder.testManager.afterTestClass()
+ }
+ }
+
+ spec.allFeatures*.addIterationInterceptor { invocation ->
+ holder.testManager.beforeTest(invocation.instance.getClass(), invocation.iteration.displayName)
+ try {
+ invocation.proceed()
+ } finally {
+ holder.testManager.afterTest()
+ }
+ }
+
+ addGebExtensionOnFailureReporter(spec)
+
+ GebRecordingTestListener recordingListener = new GebRecordingTestListener(
+ holder
+ )
+ spec.addListener(recordingListener)
+ }
+ }
+
+ @TailRecursive
+ private boolean isContainerGebSpec(SpecInfo spec) {
+ if (spec != null) {
+ if (spec.filename.startsWith("${ContainerGebSpec.simpleName}." as String)) {
+ return true
+ }
+ return isContainerGebSpec(spec.superSpec)
+ }
+ return false
+ }
+
+ private static boolean validateContainerGebSpec(SpecInfo specInfo) {
+ if (!specInfo.annotations.find { it.annotationType() == Integration }) {
+ throw new IllegalArgumentException('ContainerGebSpec classes must be annotated with @Integration')
+ }
+
+ return true
+ }
+
+ private static void addGebExtensionOnFailureReporter(SpecInfo spec) {
+ List This is useful when using any of the {@code download*()} methods as they will connect from the host,
+ * and not from within the container.
+ * 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() {
+ return hostNameChanged ? currentContainer.host : DEFAULT_HOSTNAME_FROM_HOST
+ }
+
+ private boolean isHostNameChanged() {
+ return currentContainer.host != ContainerGebConfiguration.DEFAULT_HOSTNAME_FROM_CONTAINER
+ }
+
@CompileStatic
@EqualsAndHashCode
private static class WebDriverContainerConfiguration {
String protocol
String hostName
- int port
+ boolean reporting
- WebDriverContainerConfiguration(int port, SpecInfo spec) {
+ WebDriverContainerConfiguration(SpecInfo spec) {
ContainerGebConfiguration configuration = spec.annotations.find {
it.annotationType() == ContainerGebConfiguration
} as ContainerGebConfiguration
protocol = configuration?.protocol() ?: ContainerGebConfiguration.DEFAULT_PROTOCOL
hostName = configuration?.hostName() ?: ContainerGebConfiguration.DEFAULT_HOSTNAME_FROM_CONTAINER
- this.port = port
+ reporting = configuration?.reporting() ?: false
}
}
}
diff --git a/src/testFixtures/resources/META-INF/services/org.spockframework.runtime.extension.IGlobalExtension b/src/testFixtures/resources/META-INF/services/org.spockframework.runtime.extension.IGlobalExtension
index 893fab6..cd6ea72 100644
--- a/src/testFixtures/resources/META-INF/services/org.spockframework.runtime.extension.IGlobalExtension
+++ b/src/testFixtures/resources/META-INF/services/org.spockframework.runtime.extension.IGlobalExtension
@@ -1 +1 @@
-grails.plugin.geb.ContainerGebRecordingExtension
\ No newline at end of file
+grails.plugin.geb.GrailsContainerGebExtension
\ No newline at end of file