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)
     }
 }