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/>