You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by ja...@apache.org on 2026/07/22 17:41:20 UTC
(grails-core) 03/04: add Playwright Geb example and stress coverage
This is an automated email from the ASF dual-hosted git repository.
jamesfredley pushed a commit to branch feature/grails-geb-playwright-local
in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 8b5ac75fb7679b23ba8170a9524e03cbd0c79452
Author: James Fredley <ja...@users.noreply.github.com>
AuthorDate: Wed Jul 22 13:40:49 2026 -0400
add Playwright Geb example and stress coverage
Exercise context-path navigation, GebConfig driver wiring, delayed DOM
waits, typing/click stress, and local file upload without Testcontainers.
---
.../org/demo/contextpath/ContextPathSpec.groovy | 4 +-
.../groovy/org/demo/spock/GebConfigSpec.groovy | 28 ++++--------
.../integration-test/resources/GebConfig.groovy | 21 ++-------
.../org/demo/spock/PlaywrightStressSpec.groovy | 52 ++++++++++++++++++++++
.../org/demo/spock/PlaywrightUploadSpec.groovy} | 33 ++++++--------
5 files changed, 80 insertions(+), 58 deletions(-)
diff --git a/grails-test-examples/geb-context-path/src/integration-test/groovy/org/demo/contextpath/ContextPathSpec.groovy b/grails-test-examples/geb-context-path/src/integration-test/groovy/org/demo/contextpath/ContextPathSpec.groovy
index 1d36ebd194..94bffed09c 100644
--- a/grails-test-examples/geb-context-path/src/integration-test/groovy/org/demo/contextpath/ContextPathSpec.groovy
+++ b/grails-test-examples/geb-context-path/src/integration-test/groovy/org/demo/contextpath/ContextPathSpec.groovy
@@ -22,7 +22,7 @@ package org.demo.contextpath
import org.demo.contextpath.pages.GreetingPage
import org.demo.contextpath.pages.HomePage
-import grails.plugin.geb.ContainerGebSpec
+import grails.plugin.geb.PlaywrightGebSpec
import grails.testing.mixin.integration.Integration
/**
@@ -31,7 +31,7 @@ import grails.testing.mixin.integration.Integration
* in the base URL, page navigation would result in 404 errors.
*/
@Integration
-class ContextPathSpec extends ContainerGebSpec {
+class ContextPathSpec extends PlaywrightGebSpec {
void 'should navigate to the home page under the configured context path'() {
expect: 'visiting the home page'
diff --git a/grails-test-examples/geb-gebconfig/src/integration-test/groovy/org/demo/spock/GebConfigSpec.groovy b/grails-test-examples/geb-gebconfig/src/integration-test/groovy/org/demo/spock/GebConfigSpec.groovy
index 830a716dea..128b8fc168 100644
--- a/grails-test-examples/geb-gebconfig/src/integration-test/groovy/org/demo/spock/GebConfigSpec.groovy
+++ b/grails-test-examples/geb-gebconfig/src/integration-test/groovy/org/demo/spock/GebConfigSpec.groovy
@@ -19,36 +19,26 @@
package org.demo.spock
-import org.openqa.selenium.remote.RemoteWebDriver
+import geb.direct.PlaywrightWebDriver
import org.demo.spock.pages.HomePage
-import grails.plugin.geb.ContainerGebSpec
+import grails.plugin.geb.PlaywrightGebSpec
import grails.testing.mixin.integration.Integration
/**
- * Test spec to verify that our custom GebConfig.groovy driver configuration
- * is being used instead of the default WebDriverContainerHolder configuration.
+ * Test spec to verify that the Playwright driver configuration is used.
*/
@Integration
-class GebConfigSpec extends ContainerGebSpec {
+class GebConfigSpec extends PlaywrightGebSpec {
- void 'should use custom RemoteWebDriver from GebConfig.groovy'() {
- expect: 'the driver to be a RemoteWebDriver'
- driver instanceof RemoteWebDriver
-
- when: 'getting the capabilities of the driver'
- def capabilities = ((RemoteWebDriver) driver).capabilities
-
- then: 'our custom capability set in GebConfig is available'
- capabilities.getCapability('grails:gebConfigUsed') == true
-
- and: 'the driver should have Firefox-specific capabilities'
- capabilities.browserName == 'firefox'
+ void 'should use PlaywrightWebDriver from GebConfig.groovy'() {
+ expect: 'the driver is the local Playwright adapter'
+ driver instanceof PlaywrightWebDriver
when: 'navigating to a page'
to(HomePage)
- then: 'the session should be active'
- driver.sessionId != null
+ then: 'the browser has an active page'
+ ((PlaywrightWebDriver) driver).page != null
}
}
diff --git a/grails-test-examples/geb-gebconfig/src/integration-test/resources/GebConfig.groovy b/grails-test-examples/geb-gebconfig/src/integration-test/resources/GebConfig.groovy
index 963250f647..b1234e1345 100644
--- a/grails-test-examples/geb-gebconfig/src/integration-test/resources/GebConfig.groovy
+++ b/grails-test-examples/geb-gebconfig/src/integration-test/resources/GebConfig.groovy
@@ -19,27 +19,14 @@
import geb.report.ReportState
import geb.report.Reporter
-import org.openqa.selenium.firefox.FirefoxOptions
-import org.openqa.selenium.remote.RemoteWebDriver
+import geb.direct.PlaywrightDriver
import geb.report.ReportingListener
-// Configuration for container-based Geb testing.
-// This driver configuration will be used by WebDriverContainerHolder.
-driver = {
-
- // The remote address will be set by WebDriverContainerHolder via
- // system property `webdriver.remote.server` before this closure is called.
- new RemoteWebDriver(new FirefoxOptions().tap {
- // Add a custom capability that we can test for
- // to verify our configuration is being used.
- setCapability('grails:gebConfigUsed', true)
- })
+driver = PlaywrightDriver.config {
+ browserType = 'chromium'
+ headless = true
}
-// The `containerBrowser` property must match the configured
-// driver in order to start up a matching Selenium browser container.
-containerBrowser = 'firefox'
-
// Another proof that GebConfig.groovy is being utilized, next to GebConfigSpec.
reportingListener = new ReportingListener() {
void onReport(Reporter reporter, ReportState reportState, List<File> reportFiles) {
diff --git a/grails-test-examples/geb/src/integration-test/groovy/org/demo/spock/PlaywrightStressSpec.groovy b/grails-test-examples/geb/src/integration-test/groovy/org/demo/spock/PlaywrightStressSpec.groovy
new file mode 100644
index 0000000000..a0048a9de7
--- /dev/null
+++ b/grails-test-examples/geb/src/integration-test/groovy/org/demo/spock/PlaywrightStressSpec.groovy
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.demo.spock
+
+import org.openqa.selenium.JavascriptExecutor
+import org.demo.spock.pages.HomePage
+
+import grails.plugin.geb.PlaywrightGebSpec
+import grails.testing.mixin.integration.Integration
+
+@Integration
+class PlaywrightStressSpec extends PlaywrightGebSpec {
+
+ void 'should wait for delayed content and handle repeated type and click interactions'() {
+ given:
+ to(HomePage)
+ JavascriptExecutor javascript = driver as JavascriptExecutor
+ javascript.executeScript('''
+ document.body.insertAdjacentHTML('beforeend',
+ '<input id="playwright-input"><button id="playwright-button">Submit</button><p id="playwright-result"></p>');
+ document.querySelector('#playwright-button').addEventListener('click', () => {
+ document.querySelector('#playwright-result').textContent = document.querySelector('#playwright-input').value;
+ });
+ setTimeout(() => document.querySelector('#playwright-result').dataset.ready = 'true', 150);
+ ''')
+
+ when:
+ $('#playwright-input') << 'grails-playwright'
+ $('#playwright-button').click()
+
+ then:
+ waitFor { $('#playwright-result').text() == 'grails-playwright' }
+ waitFor { $('#playwright-result').attr('data-ready') == 'true' }
+ }
+
+}
diff --git a/grails-test-examples/geb-context-path/src/integration-test/groovy/org/demo/contextpath/ContextPathSpec.groovy b/grails-test-examples/geb/src/integration-test/groovy/org/demo/spock/PlaywrightUploadSpec.groovy
similarity index 52%
copy from grails-test-examples/geb-context-path/src/integration-test/groovy/org/demo/contextpath/ContextPathSpec.groovy
copy to grails-test-examples/geb/src/integration-test/groovy/org/demo/spock/PlaywrightUploadSpec.groovy
index 1d36ebd194..f5cbabc4ab 100644
--- a/grails-test-examples/geb-context-path/src/integration-test/groovy/org/demo/contextpath/ContextPathSpec.groovy
+++ b/grails-test-examples/geb/src/integration-test/groovy/org/demo/spock/PlaywrightUploadSpec.groovy
@@ -16,33 +16,26 @@
* specific language governing permissions and limitations
* under the License.
*/
+package org.demo.spock
-package org.demo.contextpath
+import org.demo.spock.pages.UploadPage
+import org.demo.spock.pages.UploadSuccessPage
-import org.demo.contextpath.pages.GreetingPage
-import org.demo.contextpath.pages.HomePage
-
-import grails.plugin.geb.ContainerGebSpec
+import grails.plugin.geb.PlaywrightGebSpec
import grails.testing.mixin.integration.Integration
-/**
- * Verifies that ContainerGebSpec correctly includes the server's
- * context path in the browser's base URL. Without the context path
- * in the base URL, page navigation would result in 404 errors.
- */
@Integration
-class ContextPathSpec extends ContainerGebSpec {
+class PlaywrightUploadSpec extends PlaywrightGebSpec {
- void 'should navigate to the home page under the configured context path'() {
- expect: 'visiting the home page'
- to(HomePage)
- }
+ void 'should upload a local file without a container file detector'() {
+ given:
+ UploadPage uploadPage = to(UploadPage)
- void 'should navigate to a controller under the configured context path'() {
- when: 'visiting a controller page'
- to(GreetingPage)
+ when:
+ uploadPage.fileInput.file = new File('src/integration-test/resources/assets/upload-test.txt')
+ uploadPage.submitBtn.click()
- then: 'the controller action is reached and renders correctly'
- messageText == 'Hello from Grails'
+ then:
+ at(UploadSuccessPage)
}
}