This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/struts.git


The following commit(s) were added to refs/heads/main by this push:
     new 71a3c6548 WW-5702 test(core): render pattern, required-on-radio and 
required-on-file end to end (#1936)
71a3c6548 is described below

commit 71a3c654828b43479759db6e1afbdfaba1351484
Author: Lukasz Lenart <[email protected]>
AuthorDate: Mon Sep 14 09:18:41 2026 +0200

    WW-5702 test(core): render pattern, required-on-radio and required-on-file 
end to end (#1936)
    
    The ticket's remaining test asks: only minlength was asserted through a
    template. Adds pattern on a text field, required on every radio of a
    group (radiomap.ftl includes common-attributes once per option) and on
    a file input, plus a guard that the text half of a combobox keeps its
    constraints — combobox.ftl reaches constraints.ftl through text.ftl.
    
    Item 12 (six templates that "can never render constraints") needs no
    change: combobox already does, datetextfield is a JavaTemplates-only
    stub, and doubleselect, updownselect, optiontransferselect and
    inputtransferselect render a "not supported in this theme" div with no
    input for a constraint to land on. Each new test was run once with the
    common-attributes include removed from the templates to confirm it
    fails.
    
    Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
 .../struts2/components/ConstraintAction.java       | 29 +++++++++
 .../views/jsp/ui/Html5ConstraintRenderingTest.java | 73 +++++++++++++++++++---
 .../components/ConstraintAction-validation.xml     | 18 ++++++
 3 files changed, 112 insertions(+), 8 deletions(-)

diff --git 
a/core/src/test/java/org/apache/struts2/components/ConstraintAction.java 
b/core/src/test/java/org/apache/struts2/components/ConstraintAction.java
index 606d163da..fc75b472a 100644
--- a/core/src/test/java/org/apache/struts2/components/ConstraintAction.java
+++ b/core/src/test/java/org/apache/struts2/components/ConstraintAction.java
@@ -28,6 +28,9 @@ public class ConstraintAction extends ActionSupport {
     private String bio;
     private String nickname;
     private ConstraintUser user;
+    private String code;
+    private String choice;
+    private Object attachment;
 
     public String getUsername() {
         return username;
@@ -65,6 +68,32 @@ public class ConstraintAction extends ActionSupport {
         this.nickname = nickname;
     }
 
+    public String getCode() {
+        return code;
+    }
+
+    @StrutsParameter
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getChoice() {
+        return choice;
+    }
+
+    @StrutsParameter
+    public void setChoice(String choice) {
+        this.choice = choice;
+    }
+
+    public Object getAttachment() {
+        return attachment;
+    }
+
+    public void setAttachment(Object attachment) {
+        this.attachment = attachment;
+    }
+
     @StrutsParameter(depth = 1)
     public ConstraintUser getUser() {
         return user;
diff --git 
a/core/src/test/java/org/apache/struts2/views/jsp/ui/Html5ConstraintRenderingTest.java
 
b/core/src/test/java/org/apache/struts2/views/jsp/ui/Html5ConstraintRenderingTest.java
index c5979e36d..b6717b2f4 100644
--- 
a/core/src/test/java/org/apache/struts2/views/jsp/ui/Html5ConstraintRenderingTest.java
+++ 
b/core/src/test/java/org/apache/struts2/views/jsp/ui/Html5ConstraintRenderingTest.java
@@ -24,6 +24,7 @@ import org.apache.struts2.mock.MockActionProxy;
 import org.apache.struts2.views.jsp.AbstractUITagTest;
 
 import java.util.HashMap;
+import java.util.function.Supplier;
 
 public class Html5ConstraintRenderingTest extends AbstractUITagTest {
 
@@ -85,6 +86,55 @@ public class Html5ConstraintRenderingTest extends 
AbstractUITagTest {
             output.contains("Contains \"quotes\" and <brackets>"));
     }
 
+    public void testRendersPatternOnATextField() throws Exception {
+        String output = render("true", "code", null);
+
+        assertTrue("expected pattern in: " + output, 
output.contains("pattern=\"^[A-Z]{3}\\d{2}$\""));
+    }
+
+    /**
+     * radiomap.ftl includes common-attributes.ftl once per option, so every 
input of the group
+     * carries the attribute; HTML applies {@code required} to the group as a 
whole.
+     */
+    public void testRendersRequiredOnEveryRadioOfTheGroup() throws Exception {
+        String output = renderTag("true", () -> {
+            RadioTag radio = new RadioTag();
+            radio.setName("choice");
+            radio.setList("{'yes','no'}");
+            return radio;
+        });
+
+        assertEquals("expected required on both radios in: " + output,
+            2, output.split("required=\"required\"", -1).length - 1);
+    }
+
+    public void testRendersRequiredOnAFileInput() throws Exception {
+        String output = renderTag("true", () -> {
+            FileTag file = new FileTag();
+            file.setName("attachment");
+            return file;
+        });
+
+        assertTrue("expected required in: " + output,
+            output.contains("type=\"file\" name=\"attachment\"") && 
output.contains("required=\"required\""));
+    }
+
+    /**
+     * combobox.ftl reaches constraints.ftl through html5/text.ftl, so the 
text half of the control
+     * already carries constraints; this pins that against a template rewrite.
+     */
+    public void testRendersConstraintsOnTheTextHalfOfACombobox() throws 
Exception {
+        String output = renderTag("true", () -> {
+            ComboBoxTag combo = new ComboBoxTag();
+            combo.setName("username");
+            combo.setList("{'a','b'}");
+            return combo;
+        });
+
+        assertTrue("expected minlength on the text input in: " + output,
+            output.contains("name=\"username\" value=\"\" 
id=\"constraintAction_username\" minlength=\"3\""));
+    }
+
     private String render(String constraintsEnabled) throws Exception {
         return render(constraintsEnabled, "username", null);
     }
@@ -98,6 +148,20 @@ public class Html5ConstraintRenderingTest extends 
AbstractUITagTest {
     }
 
     private String render(String constraintsEnabled, String fieldName, String 
requiredLabel, String maxlength) throws Exception {
+        return renderTag(constraintsEnabled, () -> {
+            TextFieldTag field = new TextFieldTag();
+            field.setName(fieldName);
+            if (requiredLabel != null) {
+                field.setRequiredLabel(requiredLabel);
+            }
+            if (maxlength != null) {
+                field.setMaxlength(maxlength);
+            }
+            return field;
+        });
+    }
+
+    private String renderTag(String constraintsEnabled, 
Supplier<AbstractUITag> tagFactory) throws Exception {
         initDispatcher(new HashMap<String, String>() {{
             put("configProviders", TestConfigurationProvider.class.getName());
             put(StrutsConstants.STRUTS_UI_HTML5_CONSTRAINTS, 
constraintsEnabled);
@@ -112,16 +176,9 @@ public class Html5ConstraintRenderingTest extends 
AbstractUITagTest {
         form.setNamespace("");
         form.doStartTag();
 
-        TextFieldTag field = new TextFieldTag();
+        AbstractUITag field = tagFactory.get();
         field.setPageContext(pageContext);
         field.setTheme("html5");
-        field.setName(fieldName);
-        if (requiredLabel != null) {
-            field.setRequiredLabel(requiredLabel);
-        }
-        if (maxlength != null) {
-            field.setMaxlength(maxlength);
-        }
         field.doStartTag();
         field.doEndTag();
         form.doEndTag();
diff --git 
a/core/src/test/resources/org/apache/struts2/components/ConstraintAction-validation.xml
 
b/core/src/test/resources/org/apache/struts2/components/ConstraintAction-validation.xml
index cadbb050a..6c847a3c3 100644
--- 
a/core/src/test/resources/org/apache/struts2/components/ConstraintAction-validation.xml
+++ 
b/core/src/test/resources/org/apache/struts2/components/ConstraintAction-validation.xml
@@ -40,6 +40,24 @@
             <message>bio must be at most ${maxLength} characters</message>
         </field-validator>
     </field>
+    <field name="code">
+        <field-validator type="regex">
+            <param name="regex"><![CDATA[^[A-Z]{3}\d{2}$]]></param>
+            <param name="trim">false</param>
+            <param name="caseSensitive">true</param>
+            <message>code must be three letters and two digits</message>
+        </field-validator>
+    </field>
+    <field name="choice">
+        <field-validator type="required">
+            <message>pick one</message>
+        </field-validator>
+    </field>
+    <field name="attachment">
+        <field-validator type="required">
+            <message>attach a file</message>
+        </field-validator>
+    </field>
     <field name="user">
         <field-validator type="visitor">
             <message/>

Reply via email to