View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host;
16  
17  import org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.javascript.host.xml.XMLDocumentTest;
19  import org.htmlunit.junit.BrowserRunner;
20  import org.htmlunit.junit.annotation.Alerts;
21  import org.htmlunit.util.MimeType;
22  import org.junit.Test;
23  import org.junit.runner.RunWith;
24  
25  /**
26   * Tests for {@link org.htmlunit.javascript.host.NamedNodeMap}.
27   *
28   * @author Marc Guillemot
29   * @author Daniel Gredler
30   * @author Ahmed Ashour
31   * @author Frank Danek
32   * @author Ronald Brill
33   */
34  @RunWith(BrowserRunner.class)
35  public class NamedNodeMapTest extends WebDriverTestCase {
36  
37      /**
38       * @throws Exception if an error occurs
39       */
40      @Test
41      @Alerts({"name=f", "id=f", "foo=bar", "baz=blah"})
42      public void attributes() throws Exception {
43          final String html = DOCTYPE_HTML
44              + "<html>\n"
45              + "<head>\n"
46              + "<script>\n"
47              + LOG_TITLE_FUNCTION
48              + "  function test() {\n"
49              + "    var f = document.getElementById('f');\n"
50              + "    for(var i = 0; i < f.attributes.length; i++) {\n"
51              + "      if (f.attributes[i]) {\n"
52              + "        log(f.attributes[i].name + '=' + f.attributes[i].value);\n"
53              + "      } else {\n"
54              + "        log(i);\n"
55              + "      }\n"
56              + "    }\n"
57              + "  }\n"
58              + "</script>\n"
59              + "</head>\n"
60              + "<body onload='test()'>\n"
61              + "<form name='f' id='f' foo='bar' baz='blah'></form>\n"
62              + "</body>\n"
63              + "</html>";
64  
65          loadPageVerifyTitle2(html);
66      }
67  
68      /**
69       * @throws Exception if an error occurs
70       */
71      @Test
72      @Alerts({"name=f", "id=f", "foo=bar", "baz=blah"})
73      public void attributesForOf() throws Exception {
74          final String html = DOCTYPE_HTML
75              + "<html>\n"
76              + "<head>\n"
77              + "<script>\n"
78              + LOG_TITLE_FUNCTION
79              + "  function test() {\n"
80              + "    var f = document.getElementById('f');\n"
81              + "    for (var attr of f.attributes) {\n"
82              + "      if (attr) {\n"
83              + "        log(attr.name + '=' + attr.value);\n"
84              + "      } else {\n"
85              + "        log(i);\n"
86              + "      }\n"
87              + "    }\n"
88              + "  }\n"
89              + "</script>\n"
90              + "</head>\n"
91              + "<body onload='test()'>\n"
92              + "<form name='f' id='f' foo='bar' baz='blah'></form>\n"
93              + "</body>\n"
94              + "</html>";
95  
96          loadPageVerifyTitle2(html);
97      }
98  
99      /**
100      * @throws Exception if an error occurs
101      */
102     @Test
103     @Alerts({"name", "f", "name", "f", "name", "f", "name", "f", "null"})
104     public void getNamedItem_HTML() throws Exception {
105         final String html = DOCTYPE_HTML
106             + "<html>\n"
107             + "<head>\n"
108             + "<script>\n"
109             + LOG_TITLE_FUNCTION
110             + "  function test() {\n"
111             + "    var f = document.getElementById('f');\n"
112             + "    log(f.attributes.getNamedItem('name').nodeName);\n"
113             + "    log(f.attributes.getNamedItem('name').nodeValue);\n"
114             + "    log(f.attributes.getNamedItem('NaMe').nodeName);\n"
115             + "    log(f.attributes.getNamedItem('nAmE').nodeValue);\n"
116             + "    try {\n"
117             + "      log(f.attributes.name.nodeName);\n"
118             + "      log(f.attributes.name.nodeValue);\n"
119             + "    } catch(e) { logEx(e); }\n"
120             + "    try {\n"
121             + "      log(f.attributes.NaMe.nodeName);\n"
122             + "      log(f.attributes.nAmE.nodeValue);\n"
123             + "    } catch(e) { logEx(e); }\n"
124             + "    log(f.attributes.getNamedItem('notExisting'));\n"
125             + "  }\n"
126             + "</script>\n"
127             + "</head>\n"
128             + "<body onload='test()'>\n"
129             + "<form name='f' id='f' foo='bar' baz='blah'></form>\n"
130             + "</body>\n"
131             + "</html>";
132 
133         loadPageVerifyTitle2(html);
134     }
135 
136     /**
137      * @throws Exception if the test fails
138      */
139     @Test
140     @Alerts({"myattr", "myattr2", "myattr", "myattr2", "myattr2"})
141     public void getNamedItem_HTML_Case() throws Exception {
142         final String html = DOCTYPE_HTML
143             + "<html><head>\n"
144             + "<script>\n"
145             + LOG_TITLE_FUNCTION
146             + "  function test() {\n"
147             + "    var elem = document.getElementById('tester');\n"
148 
149             + "    var node = document.createAttribute('myAttr');\n"
150             + "    elem.attributes.setNamedItem(node);\n"
151 
152             + "    var node = document.createAttribute('myattr2');\n"
153             + "    elem.attributes.setNamedItem(node);\n"
154 
155             + "    for(var i = 0; i < elem.attributes.length; i++) {\n"
156             + "      var name = elem.attributes[i].name;\n"
157             + "      if (name.indexOf('my') === 0) { log(name); }\n"
158             + "    }\n"
159 
160             + "    var item = elem.attributes.getNamedItem('myAttr');\n"
161             + "    if (item) {\n"
162             + "      log(item.nodeName);\n"
163             + "    } else {\n"
164             + "      log('not found');\n"
165             + "    }\n"
166 
167             + "    log(elem.attributes.getNamedItem('myattr2').name);\n"
168             + "    log(elem.attributes.getNamedItem('MYaTTr2').name);\n"
169             + "  }\n"
170             + "</script></head><body onload='test()'>\n"
171             + "  <div id='tester'></div>\n"
172             + "</body></html>";
173 
174         loadPageVerifyTitle2(html);
175     }
176 
177     /**
178      * @throws Exception if an error occurs
179      */
180     @Test
181     @Alerts({"name", "y", "name", "y", "null", "undefined", "null"})
182     public void getNamedItem_XML() throws Exception {
183         final String html = DOCTYPE_HTML
184             + "<html><head>\n"
185             + "<script>\n"
186             + LOG_TITLE_FUNCTION
187             + "  function test() {\n"
188             + "    var doc = " + XMLDocumentTest.callLoadXMLDocumentFromFile("'second.xml'") + ";\n"
189             + "    log(doc.documentElement.attributes.getNamedItem('name').nodeName);\n"
190             + "    log(doc.documentElement.attributes.getNamedItem('name').nodeValue);\n"
191             + "    try {\n"
192             + "      log(doc.documentElement.attributes.name.nodeName);\n"
193             + "      log(doc.documentElement.attributes.name.nodeValue);\n"
194             + "    } catch(e) { logEx(e); }\n"
195             + "    log(doc.documentElement.attributes.getNamedItem('NaMe'));\n"
196             + "    log(doc.documentElement.attributes.NaMe);\n"
197             + "    log(doc.documentElement.attributes.getNamedItem('nonExistent'));\n"
198             + "  }\n"
199             + XMLDocumentTest.LOAD_XML_DOCUMENT_FROM_FILE_FUNCTION
200             + "</script></head><body onload='test()'>\n"
201             + "</body></html>";
202 
203         final String xml = "<blah name='y'></blah>";
204 
205         getMockWebConnection().setDefaultResponse(xml, MimeType.TEXT_XML);
206         loadPageVerifyTitle2(html);
207     }
208 
209     /**
210      * @throws Exception if the test fails
211      */
212     @Test
213     @Alerts("myattr")
214     public void setNamedItem_HTML() throws Exception {
215         final String html = DOCTYPE_HTML
216             + "<html><head>\n"
217             + "<script>\n"
218             + LOG_TITLE_FUNCTION
219             + "  function test() {\n"
220             + "    var node = document.createAttribute('myattr');\n"
221             + "    var elem = document.getElementById('tester');\n"
222             + "    elem.attributes.setNamedItem(node);\n"
223             + "    var item = elem.attributes.getNamedItem('myAttr');\n"
224             + "    if (item) {\n"
225             + "      log(item.nodeName);\n"
226             + "    } else {\n"
227             + "      log('not found');\n"
228             + "    }\n"
229             + "  }\n"
230             + "</script></head><body onload='test()'>\n"
231             + "  <div id='tester'></div\n"
232             + "</body></html>";
233 
234         loadPageVerifyTitle2(html);
235     }
236 
237     /**
238      * @throws Exception if the test fails
239      */
240     @Test
241     @Alerts("myAttr")
242     public void setNamedItem_XML() throws Exception {
243         final String html = DOCTYPE_HTML
244             + "<html><head>\n"
245             + "<script>\n"
246             + LOG_TITLE_FUNCTION
247             + "  function test() {\n"
248             + "    var doc = " + XMLDocumentTest.callLoadXMLDocumentFromFile("'" + URL_SECOND + "'") + ";\n"
249             + "    var node = doc.createAttribute('myAttr');\n"
250             + "    doc.documentElement.attributes.setNamedItem(node);\n"
251             + "    log(doc.documentElement.attributes.getNamedItem('myAttr').nodeName);\n"
252             + "  }\n"
253             + XMLDocumentTest.LOAD_XML_DOCUMENT_FROM_FILE_FUNCTION
254             + "</script></head><body onload='test()'>\n"
255             + "  <div id='tester'></div\n"
256             + "</body></html>";
257 
258         final String xml = "<test></test>";
259 
260         getMockWebConnection().setResponse(URL_SECOND, xml, MimeType.TEXT_XML);
261         loadPageVerifyTitle2(html);
262     }
263 
264     /**
265      * @throws Exception on test failure
266      */
267     @Test
268     @Alerts({"true", "[object Attr]", "true", "[object Attr]"})
269     public void has() throws Exception {
270         final String html = DOCTYPE_HTML
271             + "<html ng-app><body>\n"
272             + "<script>\n"
273             + LOG_TITLE_FUNCTION
274             + "var attributes = document.documentElement.attributes;\n"
275             + "log(0 in attributes);\n"
276             + "log(attributes[0]);\n"
277             + "log('0' in attributes);\n"
278             + "log(attributes['0']);\n"
279             + "</script>\n"
280             + "</body></html>";
281 
282         loadPageVerifyTitle2(html);
283     }
284 
285     /**
286      * @throws Exception if an error occurs
287      */
288     @Test
289     @Alerts({"div1", ""})
290     public void removeNamedItem() throws Exception {
291         final String html = DOCTYPE_HTML
292             + "<html>\n"
293             + "<body>\n"
294             + "<div id='div1' style='background-color:#FFFFC1;'>div1</div>\n"
295             + "<script>\n"
296             + LOG_TITLE_FUNCTION
297             + "  var el = document.getElementById('div1');\n"
298             + "  log(el.id);\n"
299             + "  el.attributes.removeNamedItem('id');\n"
300             + "  log(el.id);\n"
301             + "</script>\n"
302             + "</body>\n"
303             + "</html>";
304 
305         loadPageVerifyTitle2(html);
306     }
307 
308     /**
309      * @throws Exception if an error occurs
310      */
311     @Test
312     @Alerts({"undefined", "undefined", "undefined"})
313     public void unspecifiedAttributes() throws Exception {
314         final String html = DOCTYPE_HTML
315             + "<html>\n"
316             + "<head>\n"
317             + "<script>\n"
318             + LOG_TITLE_FUNCTION
319             + "  function test() {\n"
320             + "    log(document.body.attributes.language);\n"
321             + "    log(document.body.attributes.id);\n"
322             + "    log(document.body.attributes.dir);\n"
323             + "  }\n"
324             + "</script>\n"
325             + "</head>\n"
326             + "<body onload='test()'>\n"
327             + "</body>\n"
328             + "</html>";
329 
330         loadPageVerifyTitle2(html);
331     }
332 
333     /**
334      * @throws Exception if the test fails
335      */
336     @Test
337     @Alerts("media=\"screen\"")
338     public void changedAttribute() throws Exception {
339         final String html = DOCTYPE_HTML
340             + "<html><head>\n"
341 
342             + "<style id='myStyle'>my { }</style>\n"
343 
344             + "<script>\n"
345             + LOG_TITLE_FUNCTION
346             + "function doTest() {\n"
347             + "  style = document.getElementById('myStyle');\n"
348             + "  style.media = 'screen';\n"
349 
350             + "  var attributes = style.attributes;\n"
351             + "  for (var i = 0; i < attributes.length; i++) {\n"
352             + "    if (attributes[i].name === 'media') {\n"
353             + "      log(attributes[i].name + '=\"' + attributes[i].value + '\"');\n"
354             + "    }\n"
355             + "  }\n"
356             + "}\n"
357             + "</script>\n"
358             + "</head><body onload='doTest()'>\n"
359             + "</body></html>";
360 
361         loadPageVerifyTitle2(html);
362     }
363 
364     /**
365      * See issue #1716.
366      * @throws Exception if the test fails
367      */
368     @Test
369     @Alerts("<input id=\"myinput\" name=\"test_input\">")
370     public void readAccessOnlyDefinesNewAttribs() throws Exception {
371         final String html = DOCTYPE_HTML
372               + "<html>\n"
373               + "<head>\n"
374               + "</head>\n"
375               + "<body>\n"
376               + "  <input id='myinput' name='test_input' />\n"
377               + "  <script type='text/javascript'>\n"
378               + LOG_TITLE_FUNCTION
379               + "    var input = document.getElementById('myinput');\n"
380               + "    var attrs = input.attributes;\n"
381               + "    for(var i = 0; i < attrs.length; i++) {\n"
382               + "      attrs[i];\n"
383               + "    }\n"
384               + "    log(input.outerHTML);\n"
385               + "  </script>\n"
386               + "</body>\n"
387               + "</html>";
388         loadPageVerifyTitle2(html);
389     }
390 }