Skip to content

cbmarcum/geb-container

Repository files navigation

Geb Container Library

A library to support using Testcontainers in Apache Geb integration testing.

Geb Functional Testing using Testcontainers

This library integrates Geb with Testcontainers 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 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 using this library and this project has integration tests as well.

For further reference please see the Geb documentation.

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.):

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. This requires a compatible container runtime to be installed, such as:

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 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:

./gradlew integrationTest -Dgeb.env=chrome

Reference the geb-container-sample 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:

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 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.

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.

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 and/or Selenium 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 to support observability and tracing out of the box. By default, Selenium enables tracing.

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.
  3. Your build.gradle includes the driver dependency for the chosen browser.

Example GebConfig.groovy:

driver = {
  new RemoteWebDriver(new FireFoxOptions())
}
containerBrowser = 'firefox'

Example build.gradle:

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.

About

A library to support using Testcontainers in Apache Geb integration testing.

Resources

License

Stars

Watchers

Forks

Packages

No packages published