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

dashorst pushed a commit to branch wicket-8.x
in repository https://gitbox.apache.org/repos/asf/wicket.git

commit 191c3719ae5fd6a684007804051af022360cbbe2
Author: Pedro Santos <[email protected]>
AuthorDate: Sat Oct 3 12:59:32 2026 -0300

    Pin the JavaScript a markup id is written into
    
    ComponentIdCharactersTest accepts and rejects ids and renders nothing, so 
it says
    that the check is in place and nothing about the code that relies on it. A 
sink
    that changed the quoting of its literal, the suffix the hidden fields 
container
    derives, or the precedence that makes an id attribute in the markup the 
markup id
    would leave every assertion in it passing. The new test renders a form whose
    markup gives it the id a-b_c.d1, which uses every character the check 
allows, and
    asserts the two literals that id reaches, both written into the onchange
    attribute of a field: the lookup of the form in the script that submits it, 
and
    the lookup of the hidden fields container, whose id is built from it.
    
    What the check permits and what those literals need of it are two halves of 
one
    contract, and the sinks carry nothing that says they depend on the check. 
This
    test pins behaviour rather than reproducing a defect - with the check in 
place an
    id that breaks a literal cannot be built - so it is the half that records 
the
    dependency.
    
    Co-Authored-By: Claude Fable 5 <[email protected]>
---
 .../wicket/MarkupIdInGeneratedJavaScriptTest.java  | 99 ++++++++++++++++++++++
 1 file changed, 99 insertions(+)

diff --git 
a/wicket-core/src/test/java/org/apache/wicket/MarkupIdInGeneratedJavaScriptTest.java
 
b/wicket-core/src/test/java/org/apache/wicket/MarkupIdInGeneratedJavaScriptTest.java
new file mode 100644
index 0000000000..63e203d58b
--- /dev/null
+++ 
b/wicket-core/src/test/java/org/apache/wicket/MarkupIdInGeneratedJavaScriptTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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
+ *
+ *      http://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.apache.wicket;
+
+import static org.junit.Assert.assertTrue;
+
+import org.apache.wicket.markup.IMarkupResourceStreamProvider;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.markup.html.form.Button;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.FormComponentUpdatingBehavior;
+import org.apache.wicket.markup.html.form.TextField;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.util.resource.IResourceStream;
+import org.apache.wicket.util.resource.StringResourceStream;
+import org.apache.wicket.util.tester.WicketTestCase;
+import org.junit.Test;
+
+/**
+ * Wicket writes a markup id into the JavaScript it generates without escaping 
it, and relies on the
+ * check in {@link Component} that an id contains no character able to change 
the meaning of that
+ * JavaScript. {@link ComponentIdCharactersTest} covers the check; this covers 
the other end, and
+ * pins what those literals look like for an id using every character the 
check allows.
+ */
+public class MarkupIdInGeneratedJavaScriptTest extends WicketTestCase
+{
+       /** every character a markup id may contain, beyond letters and digits 
*/
+       private static final String MARKUP_ID = "a-b_c.d1";
+
+       @Test
+       public void theMarkupIdIsWrittenIntoItsLiteralsIntact()
+       {
+               tester.startPage(new TestPage());
+
+               String response = tester.getLastResponseAsString();
+
+               // the form the script submits, from Form#getJsForListenerUrl, 
written into the onchange
+               // attribute of the field and therefore attribute-escaped 
around the id
+               assertTrue(response, 
response.contains("document.getElementById(&#039;" + MARKUP_ID + "&#039;)"));
+
+               // the container of the hidden fields, whose id is derived from 
the markup id
+               assertTrue(response,
+                       response.contains("document.getElementById(&#039;" + 
MARKUP_ID + "_hf_0&#039;)"));
+       }
+
+       /** a form whose markup gives it an id, with a default button and an 
updating behavior */
+       private static class TestPage extends WebPage implements 
IMarkupResourceStreamProvider
+       {
+               private static final long serialVersionUID = 1L;
+
+               TestPage()
+               {
+                       Form<Void> form = new Form<Void>("form")
+                       {
+                               private static final long serialVersionUID = 1L;
+
+                               @Override
+                               public String getMethod()
+                               {
+                                       return METHOD_GET;
+                               }
+                       };
+                       add(form);
+
+                       Button button = new Button("button");
+                       form.add(button);
+                       form.setDefaultButton(button);
+
+                       TextField<String> field = new 
TextField<String>("field", Model.of(""));
+                       field.add(new FormComponentUpdatingBehavior());
+                       form.add(field);
+               }
+
+               @Override
+               public IResourceStream getMarkupResourceStream(MarkupContainer 
container,
+                       Class<?> containerClass)
+               {
+                       return new 
StringResourceStream("<html><head></head><body>" +
+                               "<form wicket:id=\"form\" id=\"" + MARKUP_ID + 
"\">" +
+                               "<input wicket:id=\"field\" type=\"text\"/>" +
+                               "<input wicket:id=\"button\" type=\"submit\"/>" 
+
+                               "</form></body></html>");
+               }
+       }
+}

Reply via email to