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 c1e2a8cfa0db63c2ae2dbaee660d58e032a60e55 Author: Carl Marcum <[email protected]> AuthorDate: Thu Feb 5 19:05:25 2026 -0500 add README.md with a temporary section. --- integration/geb-testcontainers/README.md | 240 +++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) diff --git a/integration/geb-testcontainers/README.md b/integration/geb-testcontainers/README.md new file mode 100644 index 00000000..88ebd2d4 --- /dev/null +++ b/integration/geb-testcontainers/README.md @@ -0,0 +1,240 @@ +<!-- +SPDX-License-Identifier: Apache-2.0 + +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. +--> + +# Geb Testcontainer Library + +A library to support using Testcontainers in Apache Geb integration testing. + +## Work in Progress (Temporary Section) + +Currently, this library is a work in progress and is not yet ready for production use. + +Work is ongoing to fix a number of codenarc issues and remove some remaining Grails references. + +To run the build or run tests, you have to exclude the codenarc tasks. + +```shell +./gradlew check --rerun-tasks -x codenarcMain -x codenarcTest -x codenarcIntegrationTest +``` + +## Geb Functional Testing using Testcontainers + +This library integrates [Geb](https://groovy.apache.org/geb/) with [Testcontainers](https://testcontainers.com/) to make it easy to write functional tests for your applications and utilize browsers running in testcontainers and optionally record the browser using a VNC testcontainer and/or capture reporting screenshots and HTML. + +## Origins + +Much of this library was derived from the [Apache Grails - Grails-Geb module](https://github.com/apache/grails-core/tree/HEAD/grails-geb) which is used to test Grails applications with Geb using Testcontainers. + +We have modified the library to be able to test any web application running on localhost, not just a Grails application. + +The library contains class names and configuration settings that contain `Grails`. We are leaving those as-is for now. That may change in major version updates. + +## Examples + +We have a [sample project](https://github.com/cbmarcum/geb-container-sample) using this library and this project has integration tests as well. + +For further reference please see the [Geb documentation](https://groovy.apache.org/geb/). + +## Usage + +To use the library, add the following dependencies to your `build.gradle` file (adjust for the source set you're using it in, e.g., testImplementation or integrationTestImplementation.): +```groovy +dependencies { + implementation "net.codebuilders:geb-container:<latest release>" +} +``` + +There are two ways to use this library. Either extend your test classes with the `ContainerGebSpec` class or with the `GebSpec` class. + +### ContainerGebSpec (recommended) + +By extending your test classes with `ContainerGebSpec`, your tests will automatically use a containerized browser using [Testcontainers](https://java.testcontainers.org/). +This requires a [compatible container runtime](https://java.testcontainers.org/supported_docker_environment/) to be installed, such as: + +- [Docker Desktop](https://www.docker.com/products/docker-desktop/) +- [OrbStack](https://orbstack.dev/) - macOS only +- [Rancher Desktop](https://rancherdesktop.io/) +- [podman desktop](https://podman-desktop.io/) +- [Colima](https://github.com/abiosoft/colima) - macOS and Linux + +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 <your test task with ContainerGebSpec tests>` and a container will be started and configured to start a browser that can access your application under test. + +Without any additional configuration you will get a `Firefox` browser container testing a base URL of `http://localhost` on port `8080`. Firefox was chosen for [docker-selenium compatibility](https://github.com/SeleniumHQ/docker-selenium?tab=readme-ov-file#experimental-multi-arch-amd64aarch64armhf-images]) with x86_64 and aarch64 architectures. + +#### Browser Container + +The default container browser is `Firefox`. To configure a different browser you can specify a `geb.env` variable to the integrationTest task in Gradle: + +```shell +./gradlew integrationTest -Dgeb.env=chrome +``` + +Reference the [geb-container-sample GebConfig.groovy](https://github.com/cbmarcum/geb-container-sample/blob/main/app/src/integration-test/resources/GebConfig.groovy) on how to setup the environment configuration. + + +#### 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 interface `IContainerGebConfiguration` exists as an inheritable version of the annotation. + +#### Reporting (Screenshots and HTML) + +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 + +By default, no test recording will be performed. Various system properties exist to change the recording behavior. To set them, you can set them in your `build.gradle` file like so: + +```groovy +tasks.withType(Test).configureEach { + useJUnitPlatform() + systemProperty('grails.geb.recording.mode', 'RECORD_ALL') +} +``` + +* `grails.geb.recording.mode` + * purpose: which tests to record + * possible values: `SKIP`, `RECORD_ALL`, or `RECORD_FAILING` + * defaults to `SKIP` + + +* `grails.geb.recording.directory` + * purpose: the directory to save the recordings relative to the project directory + * defaults to `build/gebContainer/recordings` + + +* `grails.geb.recording.format` + * purpose: sets the format of the recording + * possible values are `FLV` or `MP4` + * defaults to `MP4` + +#### Uploads + +Uploading a file is more complicated for Remote WebDriver sessions because the file you want to upload +is likely on the host executing the tests and not in the container running the browser. +For this reason, this plugin will setup a Local File Detector by default. + +To customize the default, either: + +1. Create a class that implements [`ContainerFileDetector`](./src/testFixtures/groovy/grails/plugin/geb/ContainerFileDetector.groovy) + and specify its fully qualified class name in a `META-INF/services/grails.plugin.geb.ContainerFileDetector` file + on the classpath (e.g., `src/integration-test/resources`). +2. Use the `ContainerGebConfiguration` annotation and set its `fileDetector` property to your `ContainerFileDetector` implementation class. + +[//]: # (3. Call [`ServiceRegistry.setInstance()`](./src/testFixtures/groovy/grails/plugin/geb/serviceloader/ServiceRegistry.groovy)) +[//]: # ( in a Spock `setupSpec()` method to apply your naming convention (And use a `cleanupSpec()` to limit this to one class).) + +Alternatively, you can access the `BrowserWebDriverContainer` instance via +the `container` from within your `ContainerGebSpec` to, for example, call `.copyFileToContainer()`. +An Example of this can be seen in [ContainerSupport#createFileInputSource utility method](./src/testFixtures/groovy/grails/plugin/geb/support/ContainerSupport.groovy). + +#### Timeouts + +The following system properties exist to configure timeouts: + +* `grails.geb.atCheckWaiting.enabled` + * purpose: if `at` checks should wait for the page to be in the expected state (uses configured waiting timeout values) + * type: boolean + * defaults to `false` +* `grails.geb.timeouts.retryInterval` + * purpose: how often to retry waiting operations + * type: Number + * defaults to `0.1` seconds +* `grails.geb.timeouts.waiting` + * purpose: amount of time to wait for waiting operations + * type: Number + * defaults to `5.0` seconds +* `grails.geb.timeouts.implicitlyWait` + * purpose: amount of time the driver should wait when searching for an element if it is not immediately present. + * type: int + * defaults to `0` seconds, which means that if an element is not found, it will immediately return an error. + * Warning: Do not mix implicit and explicit waits. Doing so can cause unpredictable wait times. + Consult the [Geb](https://groovy.apache.org/geb/manual/current/#implicit-assertions-waiting) + and/or [Selenium](https://www.selenium.dev/documentation/webdriver/waits/) documentation for details. +* `grails.geb.timeouts.pageLoad` + * purpose: amount of time to wait for a page load to complete before throwing an error. + * type: int + * defaults to `300` seconds +* `grails.geb.timeouts.script` + * purpose: amount of time to wait for an asynchronous script to finish execution before throwing an error. + * type: int + * defaults to `30` seconds + +#### Observability and Tracing +Selenium integrates with [OpenTelemetry](https://opentelemetry.io) to support observability and tracing out of the box. By default, Selenium [enables tracing](https://www.selenium.dev/blog/2021/selenium-4-observability). + +This plugin, however, **disables tracing by default** since most setups lack an OpenTelemetry collector to process the traces. + +To enable tracing, set the following system property: +* `grails.geb.tracing.enabled` + * possible values are `true` or `false` + * defaults to `false` + +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 `containerBrowser` property so that `ContainerGebSpec` can start a matching container (e.g. "chrome", "edge", "firefox"). For a list of supported browsers, see the [Testcontainers documentation](https://java.testcontainers.org/modules/webdriver_containers/#other-browsers). +3. Your `build.gradle` includes the driver dependency for the chosen browser. + +Example `GebConfig.groovy`: +```groovy +driver = { + new RemoteWebDriver(new FireFoxOptions()) +} +containerBrowser = 'firefox' +``` +Example `build.gradle`: +```groovy +dependencies { + integrationTestImplementation 'org.seleniumhq.selenium:selenium-firefox-driver' +} +``` +#### Host Port + +The Grails project uses an `@Integration` annotation on container tests that injects the port into the test class, but we had to create a different approach. + +There are three ways to set the localhost port to test. + +1. Do nothing and the default is `8080`. +2. Add a `hostPort = 8090` setting to GebConfig.groovy. This setting will override the default whenever it is picked up on the test classpath. +3. Add a class level field to your container test class e.g. `int hostPort = 8000`. This will override both the default and the GebConfig.groovy for this test class. Note: this only works at the class level and not inside of a test method because it is only checked when the test class is invoked before any test setup or test is ran. + +#### Base URL + +The Grails project always used the `localhost` as the `baseUrl` setting for the container to use and any setting from the GebConfig was ignored. + +There are three ways to set a baseUrl to test. + +1. Do nothing and the default is `http://localhost:$hostPort`. +2. Add a `baseUrl = "http://groovy.apache.org"` setting to GebConfig.groovy. This setting will override the default whenever it is picked up on the test classpath. +3. Add a class level field to your container test class e.g. `String baseUrl = "http://groovy.apache.org"`. This will override both the default and the GebConfig.groovy for this test class. Note: this only works at the class level and not inside of a test method because it is only checked when the test class is invoked before any test setup or test is ran. + +`hostPort` setting is ignored anytime a `baseUrl` is configured. \ No newline at end of file
