Skip to content

Add optional geb-direct Playwright backend - #330

Open
jamesfredley wants to merge 7 commits into
apache:masterfrom
jamesfredley:feature/geb-direct-playwright
Open

Add optional geb-direct Playwright backend#330
jamesfredley wants to merge 7 commits into
apache:masterfrom
jamesfredley:feature/geb-direct-playwright

Conversation

@jamesfredley

Copy link
Copy Markdown

Summary

Optional Playwright-backed driver for Geb (geb-direct), without changing the default Selenium WebDriver path.

Geb remains WebDriver-centric. This module implements a Playwright-backed WebDriver / WebElement adapter so existing Geb surfaces (Browser, Page Objects, content DSL, $(), waitFor, modules, reporting integrations) keep working when users opt in.

Motivation

Selenium-backed browser tests are often flaky in CI: brittle waits, remote driver/container networking, and weak debugging. Playwright provides:

  • BrowserContext isolation
  • Locator auto-waiting for actionable elements
  • Strong locator strategies (role/text/test id/label/placeholder)
  • Tracing (screenshots/DOM/network)
  • Video recording
  • Network interception

geb-direct brings those strengths in as an opt-in backend.

Generic design

Concern Approach
Default Geb path Unchanged Selenium WebDriver
Opt-in driver = PlaywrightDriver.config { ... } in GebConfig
Coordinates org.apache.groovy.geb:geb-direct (same version line as other Geb modules)
Implementation Playwright Java -> Selenium WebDriver adapter
Isolation One Playwright context per driver instance
Auto-wait Locator-backed click/fill/clear
Advanced APIs PlaywrightBrowserSupport facades (network, tracing, locators, wait, storage, emulation, downloads, HAR, console, API, PDF, a11y, video)
Threading Not thread-safe; use cacheDriverPerThread under parallel workers

Configuration example

import geb.direct.PlaywrightDriver

driver = PlaywrightDriver.config {
    browserType = 'chromium' // firefox | webkit
    headless = true
    // tracing = true
    // recordVideo = true
}

Browser install

npx playwright install chromium
# or module task:
./gradlew :module:geb-direct:installPlaywrightBrowsers

Skip browser tests: -Dgeb.direct.playwright.skip=true or PLAYWRIGHT_SKIP=true.

Module layout

  • module/geb-direct - adapter + facades + tests + README
  • Manual chapter: doc/manual/src/docs/asciidoc/022-geb-direct.adoc
  • CI: Playwright Chromium install before check in build-check.yml

Verification (local)

  • 45 module tests green
  • JaCoCo line coverage gate (85%+)
  • CodeNarc + RAT clean on the module

Known initial-adapter limits

  • Not every Selenium edge case is 1:1 (some window-manager/alert paths are best-effort)
  • Selenium-style Browser.networkLatency is not mapped yet
  • Cookie APIs are scoped to the current document host (WebDriver semantics)

Grails-specific validation

Grails 8 currently drives Geb through Testcontainers + Selenium (ContainerGebSpec / BrowserWebDriverContainer). That stack is a major source of CI pain.

Selenium + Testcontainers (current Grails) Playwright local (geb-direct)
Browser Docker Selenium image Local Chromium via Playwright
App under test Host @Integration server Same
Reach app host.testcontainers.internal:port http://localhost:$serverPort
File upload Remote FileDetector / copy into container Normal local filesystem paths
Waiting Geb wait + Selenium implicit wait hazards Locator auto-wait + Geb waitFor
Recording VNC MP4 via Testcontainers Playwright video/trace
Docker required for browser Yes No

Do you still need Testcontainers with Playwright?

  • Browser: no (local Playwright is enough)
  • Databases / other infra: yes (Mongo/Postgres/etc. still fine via Testcontainers)

Proof branch on grails-core (no PR opened)

Branch (based on 8.0.x):

https://github.com/apache/grails-core/tree/feature/grails-geb-playwright-local

Adds:

  • PlaywrightGebSpec + GrailsPlaywrightGebExtension + PlaywrightBrowserHolder
  • Optional dependency on geb-direct / Geb 8.0.2-SNAPSHOT (mavenLocal for validation)
  • Tagged examples (playwright-geb): context-path, GebConfig, wait/type/click stress, local upload

Re-run on that branch:

# once
npx playwright install chromium
# from groovy-geb feature branch
./gradlew.bat publishToMavenLocal

cd <grails-core checkout of feature/grails-geb-playwright-local>
./gradlew.bat :grails-test-examples-geb:integrationTest `
  :grails-test-examples-geb-context-path:integrationTest `
  :grails-test-examples-geb-gebconfig:integrationTest `
  -PincludeTestTags=playwright-geb

Result of that validation: 5 tests, 0 failures against live Grails @Integration apps.

Mailing-list alignment

This matches the optional geb-direct / org.apache.groovy.geb direction discussed on the Groovy mailing list: keep Selenium default, add Playwright as opt-in, preserve Geb DSL.

Checklist

  • Optional module; default Selenium path untouched
  • Module tests + docs
  • CI browser install hook
  • Grails 8.0.x proof branch linked (no Grails PR)

Register the optional geb-direct submodule, Playwright 1.61 dependency,
JaCoCo coverage gate, browser install task, and CI Chromium install step.
Implement PlaywrightSession, PlaywrightWebDriver/WebElement, locator and
network helpers, tracing, waits, input, storage, emulation, and related
facades so existing Geb DSL can run on Playwright without changing the
default Selenium path.
Cover WebDriver core paths, Geb Browser/Page DSL, frames, windows, alerts,
network, locators, waits, storage, emulation, and facade helpers with a
90% JaCoCo line coverage gate.
Add module README and manual chapter covering configuration, browser
install, advanced Playwright surfaces, and Selenium default path notes.
Filter cookie reads/deletes by the active page URL/host so multi-domain
BrowserContexts match Selenium WebDriver cookie semantics.
Copilot AI review requested due to automatic review settings July 22, 2026 17:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Not ready to approve

There are a few concrete correctness/lint concerns (e.g., selector mapping edge cases and CodeNarc-triggering dead/unused imports/fields) that should be addressed before merging.

Pull request overview

Adds a new optional geb-direct module that lets Geb run on a Playwright-backed WebDriver/WebElement adapter while keeping the default Selenium WebDriver path unchanged. This introduces a Playwright session/context abstraction plus a set of “facade” helpers to expose Playwright-only capabilities (tracing, network routing, locators, etc.) through Geb’s existing Browser/DSL surfaces, along with module docs and CI setup for installing browsers.

Changes:

  • Introduces module/geb-direct with a Playwright→WebDriver adapter (PlaywrightWebDriver, PlaywrightWebElement, session + helpers).
  • Adds a comprehensive Spock test suite for adapter behavior and Playwright facades (with skip flags).
  • Updates docs, dependency catalog, Gradle wiring, and CI to install Playwright Chromium before running check.
File summaries
File Description
settings.gradle Adds the new module:geb-direct to the multi-project build.
module/geb-direct/src/test/groovy/geb/direct/support/PlaywrightSpecSupport.groovy Shared test helpers for driver creation, local server, and temp files.
module/geb-direct/src/test/groovy/geb/direct/PlaywrightWebDriverSpec.groovy Basic WebDriver surface smoke coverage (navigation/actions/JS/screenshot/locators).
module/geb-direct/src/test/groovy/geb/direct/PlaywrightWebDriverSmokeSpec.groovy Jetty-backed end-to-end WebDriver interaction smoke test.
module/geb-direct/src/test/groovy/geb/direct/PlaywrightWebDriverCoreSpec.groovy Core adapter behavior tests (timeouts, cookies, frames, actions, keys, async scripts).
module/geb-direct/src/test/groovy/geb/direct/PlaywrightWebDriverBrowserFeatureSpec.groovy Verifies Geb Browser integrations (frames/windows/uploads) against Playwright driver.
module/geb-direct/src/test/groovy/geb/direct/PlaywrightOptionsSpec.groovy Tests PlaywrightOptions defaults and copy/config behavior.
module/geb-direct/src/test/groovy/geb/direct/PlaywrightHelpersSpec.groovy Exercises helper facades (keyboard/mouse/storage/wait/emulation) on a live page.
module/geb-direct/src/test/groovy/geb/direct/PlaywrightFacadeCoverageSpec.groovy Broad facade coverage including tracing reporter, waits, routing, downloads, PDF, a11y, video.
module/geb-direct/src/test/groovy/geb/direct/PlaywrightDriverSpec.groovy Tests PlaywrightDriver.config factory behavior (independent option copies).
module/geb-direct/src/test/groovy/geb/direct/PlaywrightBySpec.groovy Tests By→Playwright selector mapping and escaping.
module/geb-direct/src/test/groovy/geb/direct/PlaywrightAlertAndWindowSpec.groovy Alert/dialog and window manager behavior tests.
module/geb-direct/src/test/groovy/geb/direct/PlaywrightAdvancedFeaturesSpec.groovy Exercises higher-level Playwright features (routing, tracing, PDF, API client, storage, console).
module/geb-direct/src/test/groovy/geb/direct/GebDirectSmokePage.groovy Simple Geb Page for verifying content DSL on the Playwright driver.
module/geb-direct/src/test/groovy/geb/direct/GebBrowserPlaywrightSpec.groovy Verifies Geb Browser/Page/content DSL works on the Playwright-backed driver.
module/geb-direct/src/main/groovy/geb/direct/report/PlaywrightTraceReporter.groovy Geb reporter that writes a trace zip and starts a new trace.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightWindow.groovy WebDriver Window adapter (viewport-based best-effort).
module/geb-direct/src/main/groovy/geb/direct/PlaywrightWebElement.groovy WebElement adapter backed by Playwright Locator with Selenium-like semantics.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightWebDriver.groovy Main WebDriver facade over a Playwright BrowserContext/Page plus helper facades.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightWait.groovy Wait facade mapping common Playwright page/context wait primitives.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightVideoSupport.groovy Small helper to access recorded video path.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightTracing.groovy Tracing start/stop wrapper over session tracing state.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightTouchscreen.groovy Touchscreen wrapper.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightTimeouts.groovy WebDriver Timeouts adapter (implicit wait + script/page load timeouts).
module/geb-direct/src/main/groovy/geb/direct/PlaywrightTargetLocator.groovy WebDriver TargetLocator adapter (frames/windows/alerts).
module/geb-direct/src/main/groovy/geb/direct/PlaywrightStorage.groovy Local/session storage helper via page evaluation.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightSession.groovy Playwright lifecycle: create/close, context options, tracing, dialog/event tracking.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightPdf.groovy Chromium PDF wrapper.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightOptions.groovy Options model + deep copy used by config factories and sessions.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightNetwork.groovy Routing/interception wrapper plus request/response wait passthrough.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightNavigation.groovy WebDriver Navigation adapter.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightMouse.groovy Mouse wrapper.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightLocators.groovy Semantic locator helpers returning Selenium WebElements.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightKeyboard.groovy Keyboard wrapper.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightHar.groovy HAR routing wrapper.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightEmulation.groovy Emulation + permissions helper wrapper.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightDriver.groovy Factory entrypoint: create and config {} driver factory closures.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightDownloads.groovy Download helper wrapper.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightCoverage.groovy Coverage facade with explicit unsupported behavior where absent.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightCookieJar.groovy Selenium-semantics cookie jar adapter scoped to current document host.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightConsole.groovy Console message + page error collection access/clear.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightBy.groovy Selenium By→Playwright selector mapping.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightBrowserSupport.groovy Entry points to access Playwright driver/page/context + helper facades from Geb Browser.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightApiClient.groovy Playwright APIRequestContext wrapper for test-side HTTP calls.
module/geb-direct/src/main/groovy/geb/direct/PlaywrightAccessibility.groovy Accessibility snapshot wrapper.
module/geb-direct/README.md Module README with setup, usage, options, and limitations.
module/geb-direct/geb-direct.gradle Module build, dependencies, skip flags, Playwright browser install task, JaCoCo gate.
gradle/libs.versions.toml Adds Playwright dependency coordinates/version.
doc/manual/src/docs/asciidoc/index.adoc Includes the new manual chapter.
doc/manual/src/docs/asciidoc/022-geb-direct.adoc New manual chapter documenting Geb Direct with Playwright.
.github/workflows/build-check.yml Installs Playwright Chromium before running check in CI.

Review details

  • Files reviewed: 51/51 changed files
  • Comments generated: 6
  • Review effort level: Low

Note

Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread module/geb-direct/src/main/groovy/geb/direct/PlaywrightBy.groovy Outdated
Comment thread module/geb-direct/src/main/groovy/geb/direct/PlaywrightHar.groovy
Comment thread module/geb-direct/src/main/groovy/geb/direct/PlaywrightWebDriver.groovy Outdated
Comment thread module/geb-direct/src/test/groovy/geb/direct/PlaywrightWebDriverCoreSpec.groovy Outdated
Apply valid review feedback for window minimize dead state, className
selector edge cases, HAR unroute clarity, and unused imports. Green
codenarcTest which was failing Build/test/quality check on CI.
@jamesfredley

Copy link
Copy Markdown
Author

Copilot review follow-up (39e0327)

Addressed the valid review comments and the CI failure:

Thread Action
previousSize unused in PlaywrightWindow Removed dead field; maximize/fullscreen are viewport best-effort; minimize is an explicit no-op
By.className digit identifiers Use [class~="..."] when not a valid CSS identifier; added unit test
unrouteFromHAR clears all routes Documented Playwright limitation; deprecated path overload; added explicit unrouteAll()
Redundant Selenium imports Dropped duplicates; kept org.openqa.selenium.*
Unused Locator import in core spec Removed (this was the codenarcTest CI break)
Path unused in PlaywrightNetwork Not valid - still used by routeFromHAR(Path) / Path.of(...)

CI

Build, test, and quality check failed on :module:geb-direct:codenarcTest (unused import), not on the Playwright tests themselves. Local verification after the fix:

  • :module:geb-direct:codenarcMain / codenarcTest green
  • :module:geb-direct:test green
  • JaCoCo gate green

All six Copilot review threads marked resolved.

ManualAnchorsSpec failed in CI because auto-generated header ids for
Installation and other sections collided with existing chapters.
@jamesfredley

Copy link
Copy Markdown
Author

CI failure root cause: ManualAnchorsSpec duplicate header ids from the new geb-direct chapter (e.g. Installation colliding with Installation & usage). Fixed in the latest commit by giving every section an explicit unique AsciiDoc anchor ([[geb-direct-...]]). Verified locally with :doc:site:test --tests geb.ManualAnchorsSpec.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants