This is an automated email from the ASF dual-hosted git repository.
borinquenkid pushed a commit to branch chore/remove-jodd-wot
in repository https://gitbox.apache.org/repos/asf/grails-core.git
The following commit(s) were added to refs/heads/chore/remove-jodd-wot by this
push:
new 3b8b35feaf Replace string assertions with Jsoup DOM parsing per review
discussion
3b8b35feaf is described below
commit 3b8b35feafd7d57471deb1d5594969cc1551a553
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Mon Jul 27 14:34:01 2026 -0500
Replace string assertions with Jsoup DOM parsing per review discussion
jdaugherty flagged the string-based assertions this PR introduced as
fragile (exact-serialization matching instead of semantic checks), and
Copilot independently raised the same concern per-assertion. jamesfredley
proposed the trade-off directly: stay dependency-free with tightened
(regex) assertions, or trade the removed jodd-wot for a real, modern
parser (Jsoup). jdaugherty chose Jsoup explicitly, anticipating more
HTML-structure-sensitive tests from planned refactoring.
Reimplements the three DefaultFieldTemplateSpec assertions against
org.jsoup instead of raw strings, restoring the exact semantic checks
the original jodd-wot/Jerry version had (root div has the fieldcontain/
error/required class tokens - order and other-attributes insensitive -
label text/for-attribute, label immediately precedes the input, and the
required-indicator span's text) rather than the newly-added brittle
literal-markup comparisons.
jsoup has no existing version management in this repo; added
jsoupVersion to gradle.properties following the same pattern already
used for javassistVersion/jnrPosixVersion, since it's a single-module,
test-only dependency.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
---
gradle.properties | 1 +
grails-fields/build.gradle | 1 +
.../formfields/DefaultFieldTemplateSpec.groovy | 34 ++++++++++++++--------
3 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/gradle.properties b/gradle.properties
index a9caae06f5..6fc832911b 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -40,6 +40,7 @@ greenmailVersion=2.1.2
javassistVersion=3.30.2-GA
jnrPosixVersion=3.1.20
joptSimpleVersion=5.0.4
+jsoupVersion=1.22.1
jspApiVersion=4.0.0
openTest4jVersion=1.3.0
picocliVersion=4.7.6
diff --git a/grails-fields/build.gradle b/grails-fields/build.gradle
index 070dc273fd..587a85b3d5 100644
--- a/grails-fields/build.gradle
+++ b/grails-fields/build.gradle
@@ -54,6 +54,7 @@ dependencies {
testImplementation project(':grails-testing-support-datamapping')
testImplementation project(':grails-testing-support-web')
testImplementation "org.javassist:javassist:$javassistVersion"
+ testImplementation "org.jsoup:jsoup:$jsoupVersion"
testRuntimeOnly 'org.objenesis:objenesis' // Required by Spock for mocking
classes without default constructor
}
diff --git
a/grails-fields/src/test/groovy/grails/plugin/formfields/DefaultFieldTemplateSpec.groovy
b/grails-fields/src/test/groovy/grails/plugin/formfields/DefaultFieldTemplateSpec.groovy
index 3c205cfb78..c3ffd95262 100644
---
a/grails-fields/src/test/groovy/grails/plugin/formfields/DefaultFieldTemplateSpec.groovy
+++
b/grails-fields/src/test/groovy/grails/plugin/formfields/DefaultFieldTemplateSpec.groovy
@@ -18,6 +18,9 @@
*/
package grails.plugin.formfields
+import org.jsoup.Jsoup
+import org.jsoup.nodes.Element
+
import grails.testing.web.taglib.TagLibUnitTest
import spock.lang.Specification
@@ -47,25 +50,26 @@ class DefaultFieldTemplateSpec extends Specification
implements TagLibUnitTest<F
void "default rendering"() {
when:
- String output = tagLib.renderDefaultField(model).toString()
+ Element root = renderRoot()
then:
- output.contains('<div class="fieldcontain">')
+ root.hasClass('fieldcontain')
+
+ and:
+ Element label = root.selectFirst('label')
+ label.text() == 'label'
+ label.attr('for') == 'property'
and:
- output.contains('<label class="" for="property">label</label>')
- output.indexOf('<label class="" for="property">label</label>') <
output.indexOf('<input name="property">')
+ label.nextElementSibling().is('input[name=property]')
}
void "container marked as invalid"() {
given:
model.invalid = true
- when:
- String output = tagLib.renderDefaultField(model).toString()
-
- then:
- output.contains('<div class="fieldcontain error">')
+ expect:
+ renderRoot().hasClass('error')
}
void "container marked as required"() {
@@ -73,13 +77,19 @@ class DefaultFieldTemplateSpec extends Specification
implements TagLibUnitTest<F
model.required = true
when:
- String output = tagLib.renderDefaultField(model).toString()
+ Element root = renderRoot()
then:
- output.contains('<div class="fieldcontain required">')
+ root.hasClass('required')
and:
- output.contains('<span class="required-indicator">*</span>')
+ Element indicator = root.selectFirst('label .required-indicator')
+ indicator.text() == '*'
+ }
+
+ private Element renderRoot() {
+ String output = tagLib.renderDefaultField(model).toString()
+ Jsoup.parseBodyFragment(output).body().children().first()
}
}