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.html;
16  
17  import org.htmlunit.WebDriverTestCase;
18  import org.htmlunit.junit.annotation.Alerts;
19  import org.junit.jupiter.api.Test;
20  
21  /**
22   * Tests for {@link HTMLTableRowElement}.
23   *
24   * @author Marc Guillemot
25   * @author Frank Danek
26   * @author Ronald Brill
27   */
28  public class HTMLTableRowElementTest extends WebDriverTestCase {
29  
30      /**
31       * @throws Exception if the test fails
32       */
33      @Test
34      @Alerts("[object HTMLTableRowElement]")
35      public void simpleScriptable() throws Exception {
36          final String html = DOCTYPE_HTML
37              + "<html><head>\n"
38              + "<script>\n"
39              + LOG_TITLE_FUNCTION
40              + "  function test() {\n"
41              + "    log(document.getElementById('myId'));\n"
42              + "  }\n"
43              + "</script>\n"
44              + "</head><body onload='test()'>\n"
45              + "  <table>\n"
46              + "    <tr id='myId'/>\n"
47              + "  </table>\n"
48              + "</body></html>";
49  
50          loadPageVerifyTitle2(html);
51      }
52  
53      /**
54       * @throws Exception if the test fails
55       */
56      @Test
57      @Alerts({"4", "td1", "3", "td2", "td4", "2", "td3",
58               "IndexSizeError/DOMException", "IndexSizeError/DOMException"})
59      public void deleteCell() throws Exception {
60          final String html = DOCTYPE_HTML
61              + "<html><head>\n"
62              + "<script>\n"
63              + LOG_TITLE_FUNCTION
64              + "  function test() {\n"
65              + "    var tr = document.getElementById('myId');\n"
66              + "    log(tr.cells.length);\n"
67              + "    log(tr.cells[0].id);\n"
68              + "    tr.deleteCell(0);\n"
69              + "    log(tr.cells.length);\n"
70              + "    log(tr.cells[0].id);\n"
71              + "    log(tr.cells[tr.cells.length-1].id);\n"
72              + "    tr.deleteCell(-1);\n"
73              + "    log(tr.cells.length);\n"
74              + "    log(tr.cells[tr.cells.length-1].id);\n"
75              + "    try { tr.deleteCell(25); } catch(e) { logEx(e); }\n"
76              + "    try { tr.deleteCell(-2); } catch(e) { logEx(e); }\n"
77              + "  }\n"
78              + "</script>\n"
79              + "</head><body onload='test()'>\n"
80              + "  <table>\n"
81              + "    <tr id='myId'/>\n"
82              + "      <td id='td1'>1</td>\n"
83              + "      <td id='td2'>2</td>\n"
84              + "      <td id='td3'>3</td>\n"
85              + "      <td id='td4'>4</td>\n"
86              + "    </tr>\n"
87              + "  </table>\n"
88              + "</body></html>";
89  
90          loadPageVerifyTitle2(html);
91      }
92  
93      /**
94       * @throws Exception if the test fails
95       */
96      @Test
97      @Alerts({"4", "TypeError", "4"})
98      public void deleteCell_noArg() throws Exception {
99          final String html = DOCTYPE_HTML
100             + "<html><head>\n"
101             + "<script>\n"
102             + LOG_TITLE_FUNCTION
103             + "  function test() {\n"
104             + "    var tr = document.getElementById('myId');\n"
105             + "    log(tr.cells.length);\n"
106             + "    try { tr.deleteCell(); } catch(e) { logEx(e); }\n"
107             + "    log(tr.cells.length);\n"
108             + "  }\n"
109             + "</script>\n"
110             + "</head><body onload='test()'>\n"
111             + "  <table>\n"
112             + "    <tr id='myId'/>\n"
113             + "      <td id='td1'>1</td>\n"
114             + "      <td id='td2'>2</td>\n"
115             + "      <td id='td3'>3</td>\n"
116             + "      <td id='td4'>4</td>\n"
117             + "    </tr>\n"
118             + "  </table>\n"
119             + "</body></html>";
120         loadPageVerifyTitle2(html);
121     }
122 
123     /**
124      * @throws Exception if an error occurs
125      */
126     @Test
127     @Alerts({"left", "right", "3", "center", "8", "foo"})
128     public void align() throws Exception {
129         final String html = DOCTYPE_HTML
130             + "<html><body><table>\n"
131             + "  <tr id='tr1' align='left'><td>a</td></tr>\n"
132             + "  <tr id='tr2' align='right'><td>b</td></tr>\n"
133             + "  <tr id='tr3' align='3'><td>c</td></tr>\n"
134             + "</table>\n"
135             + "<script>\n"
136             + LOG_TITLE_FUNCTION
137             + "  function set(e, value) {\n"
138             + "    try {\n"
139             + "      e.align = value;\n"
140             + "    } catch(e) { logEx(e); }\n"
141             + "  }\n"
142             + "  var tr1 = document.getElementById('tr1');\n"
143             + "  var tr2 = document.getElementById('tr2');\n"
144             + "  var tr3 = document.getElementById('tr3');\n"
145             + "  log(tr1.align);\n"
146             + "  log(tr2.align);\n"
147             + "  log(tr3.align);\n"
148             + "  set(tr1, 'center');\n"
149             + "  set(tr2, '8');\n"
150             + "  set(tr3, 'foo');\n"
151             + "  log(tr1.align);\n"
152             + "  log(tr2.align);\n"
153             + "  log(tr3.align);\n"
154             + "</script>\n"
155             + "</body></html>";
156 
157         loadPageVerifyTitle2(html);
158     }
159 
160     /**
161      * @throws Exception if an error occurs
162      */
163     @Test
164     @Alerts({"p", "po", "", "u", "8", "U8"})
165     public void ch() throws Exception {
166         final String html = DOCTYPE_HTML
167             + "<html><body><table>\n"
168             + "  <tr id='tr1' char='p'><td>a</td></tr>\n"
169             + "  <tr id='tr2' char='po'><td>b</td></tr>\n"
170             + "  <tr id='tr3'><td>c</td></tr>\n"
171             + "</table>\n"
172             + "<script>\n"
173             + LOG_TITLE_FUNCTION
174             + "  var tr1 = document.getElementById('tr1');\n"
175             + "  var tr2 = document.getElementById('tr2');\n"
176             + "  var tr3 = document.getElementById('tr3');\n"
177             + "  log(tr1.ch);\n"
178             + "  log(tr2.ch);\n"
179             + "  log(tr3.ch);\n"
180             + "  tr1.ch = 'u';\n"
181             + "  tr2.ch = '8';\n"
182             + "  tr3.ch = 'U8';\n"
183             + "  log(tr1.ch);\n"
184             + "  log(tr2.ch);\n"
185             + "  log(tr3.ch);\n"
186             + "</script>\n"
187             + "</body></html>";
188 
189         loadPageVerifyTitle2(html);
190     }
191 
192     /**
193      * @throws Exception if an error occurs
194      */
195     @Test
196     @Alerts({"0", "4", "", "5.2", "-3", "abc"})
197     public void chOff() throws Exception {
198         final String html = DOCTYPE_HTML
199             + "<html><body><table>\n"
200             + "  <tr id='tr1' charoff='0'><td>a</td></tr>\n"
201             + "  <tr id='tr2' charoff='4'><td>b</td></tr>\n"
202             + "  <tr id='tr3'><td>c</td></tr>\n"
203             + "</table>\n"
204             + "<script>\n"
205             + LOG_TITLE_FUNCTION
206             + "  var tr1 = document.getElementById('tr1');\n"
207             + "  var tr2 = document.getElementById('tr2');\n"
208             + "  var tr3 = document.getElementById('tr3');\n"
209             + "  log(tr1.chOff);\n"
210             + "  log(tr2.chOff);\n"
211             + "  log(tr3.chOff);\n"
212             + "  tr1.chOff = '5.2';\n"
213             + "  tr2.chOff = '-3';\n"
214             + "  tr3.chOff = 'abc';\n"
215             + "  log(tr1.chOff);\n"
216             + "  log(tr2.chOff);\n"
217             + "  log(tr3.chOff);\n"
218             + "</script>\n"
219             + "</body></html>";
220 
221         loadPageVerifyTitle2(html);
222     }
223 
224     /**
225      * @throws Exception if an error occurs
226      */
227     @Test
228     @Alerts({"top", "baseline", "3", "middle", "8", "BOTtom"})
229     public void vAlign() throws Exception {
230         final String html = DOCTYPE_HTML
231             + "<html><body><table>\n"
232             + "  <tr id='tr1' valign='top'><td>a</td></tr>\n"
233             + "  <tr id='tr2' valign='baseline'><td>b</td></tr>\n"
234             + "  <tr id='tr3' valign='3'><td>c</td></tr>\n"
235             + "</table>\n"
236             + "<script>\n"
237             + LOG_TITLE_FUNCTION
238             + "  function set(e, value) {\n"
239             + "    try {\n"
240             + "      e.vAlign = value;\n"
241             + "    } catch(e) { logEx(e); }\n"
242             + "  }\n"
243             + "  var tr1 = document.getElementById('tr1');\n"
244             + "  var tr2 = document.getElementById('tr2');\n"
245             + "  var tr3 = document.getElementById('tr3');\n"
246             + "  log(tr1.vAlign);\n"
247             + "  log(tr2.vAlign);\n"
248             + "  log(tr3.vAlign);\n"
249             + "  set(tr1, 'middle');\n"
250             + "  set(tr2, 8);\n"
251             + "  set(tr3, 'BOTtom');\n"
252             + "  log(tr1.vAlign);\n"
253             + "  log(tr2.vAlign);\n"
254             + "  log(tr3.vAlign);\n"
255             + "</script>\n"
256             + "</body></html>";
257         loadPageVerifyTitle2(html);
258     }
259 
260     /**
261      * @throws Exception if an error occurs
262      */
263     @Test
264     @Alerts({"", "#0000aa", "x"})
265     public void bgColor() throws Exception {
266         final String html = DOCTYPE_HTML
267             + "<html>\n"
268             + "  <head>\n"
269             + "    <script>\n"
270             + LOG_TITLE_FUNCTION
271             + "      function test() {\n"
272             + "        var tr = document.getElementById('tr');\n"
273             + "        log(tr.bgColor);\n"
274             + "        tr.bgColor = '#0000aa';\n"
275             + "        log(tr.bgColor);\n"
276             + "        tr.bgColor = 'x';\n"
277             + "        log(tr.bgColor);\n"
278             + "      }\n"
279             + "    </script>\n"
280             + "  </head>\n"
281             + "  <body onload='test()'>\n"
282             + "  <table><tr id='tr'><td>a</td></tr></table>\n"
283             + "  </body>\n"
284             + "</html>";
285 
286         loadPageVerifyTitle2(html);
287     }
288 
289     /**
290      * @throws Exception if an error occurs
291      */
292     @Test
293     @Alerts({"0", "0", "3", "1", "-1", "true", "false"})
294     public void rowIndex_sectionRowIndex() throws Exception {
295         final String html = DOCTYPE_HTML
296             + "<html><body><table>\n"
297             + "  <tr id='tr1'><td>a</td></tr>\n"
298             + "  <tr id='tr2'><td>b</td></tr>\n"
299             + "  <tfoot>\n"
300             + "    <tr id='trf1'><td>a</td></tr>\n"
301             + "    <tr id='trf2'><td>a</td></tr>\n"
302             + "  </tfoot>\n"
303             + "</table>\n"
304             + "<script>\n"
305             + LOG_TITLE_FUNCTION
306             + "  var tr1 = document.getElementById('tr1');\n"
307             + "  var trf2 = document.getElementById('trf2');\n"
308             + "  log(tr1.rowIndex);\n"
309             + "  log(tr1.sectionRowIndex);\n"
310             + "  log(trf2.rowIndex);\n"
311             + "  log(trf2.sectionRowIndex);\n"
312             + "  var tr3 = document.createElement('tr');\n"
313             + "  log(tr3.rowIndex);\n"
314             + "  log(tr3.sectionRowIndex == -1);\n"
315             + "  log(tr3.sectionRowIndex > 1000);\n"
316             + "</script>\n"
317             + "</body></html>";
318 
319         loadPageVerifyTitle2(html);
320     }
321 
322     /**
323      * Test for 3180939; same left offset for both
324      * rows is expected.
325      * @throws Exception if an error occurs
326      */
327     @Test
328     @Alerts("true")
329     public void offsetLeftDifferentRows() throws Exception {
330         final String html = DOCTYPE_HTML
331             + "<html><body><table>\n"
332             + "  <tr>\n"
333             + "    <td id='td_1_1'>1_1</td>\n"
334             + "    <td id='td_1_2'>1_2</td>\n"
335             + "  </tr>\n"
336             + "  <tr>\n"
337             + "    <td id='td_2_1'>2_1</td>\n"
338             + "    <td id='td_2_2'>2_2</td>\n"
339             + "  </tr>\n"
340             + "</table>\n"
341             + "<script>\n"
342             + LOG_TITLE_FUNCTION
343             + "  var o1 = document.getElementById('td_1_1').offsetLeft;\n"
344             + "  var o2 = document.getElementById('td_2_1').offsetLeft;\n"
345             + "  log(o1 == o2 ? 'true' : o1 + ' != ' + o2);\n"
346             + "</script>\n"
347             + "</body></html>";
348         loadPageVerifyTitle2(html);
349     }
350 
351     /**
352      * @throws Exception if the test fails
353      */
354     @Test
355     @Alerts({"cell1", "[object HTMLTableCellElement]", "abc", "[object Text]", ""})
356     public void innerText() throws Exception {
357         final String html = DOCTYPE_HTML
358             + "<html><body>\n"
359             + "  <table>\n"
360             + "    <tr id='tab_row'><td>cell1</td></tr>\n"
361             + "  </table>\n"
362             + "<script>\n"
363             + LOG_TITLE_FUNCTION
364             + "  var node = document.getElementById('tab_row');\n"
365             + "  log(node.innerText);\n"
366             + "  log(node.firstChild);\n"
367 
368             + "  try { node.innerText = 'abc'; } catch(e) { logEx(e); }\n"
369             + "  log(node.innerText);\n"
370             + "  log(node.firstChild);\n"
371 
372             + "  try { node.innerText = ''; } catch(e) { logEx(e); }\n"
373             + "  log(node.innerText);\n"
374             + "</script></body></html>";
375 
376         loadPageVerifyTitle2(html);
377     }
378 
379     /**
380      * @throws Exception if the test fails
381      */
382     @Test
383     @Alerts({"cell1", "[object HTMLTableCellElement]", "abc", "[object Text]", ""})
384     public void textContent() throws Exception {
385         final String html = DOCTYPE_HTML
386             + "<html><body>\n"
387             + "  <table>\n"
388             + "    <tr id='tab_row'><td>cell1</td></tr>\n"
389             + "  </table>\n"
390             + "<script>\n"
391             + LOG_TITLE_FUNCTION
392             + "  var node = document.getElementById('tab_row');\n"
393             + "  log(node.textContent);\n"
394             + "  log(node.firstChild);\n"
395 
396             + "  try { node.textContent = 'abc'; } catch(e) { logEx(e); }\n"
397             + "  log(node.textContent);\n"
398             + "  log(node.firstChild);\n"
399 
400             + "  try { node.textContent = ''; } catch(e) { logEx(e); }\n"
401             + "  log(node.textContent);\n"
402             + "</script></body></html>";
403 
404         loadPageVerifyTitle2(html);
405     }
406 
407     private void insertCell(final String cellIndex) throws Exception {
408         final String html = DOCTYPE_HTML
409             + "<html><head></head>\n"
410             + "<body>\n"
411             + "  <table>\n"
412             + "    <tr id='myRow'>\n"
413             + "      <td>first</td>\n"
414             + "      <td>second</td>\n"
415             + "    </tr>\n"
416             + "  </table>\n"
417             + "  <script>\n"
418             + LOG_TITLE_FUNCTION
419             + "    var row = document.getElementById('myRow');\n"
420             + "    log(row.cells.length);\n"
421             + "    try {\n"
422             + "      var newCell = row.insertCell(" + cellIndex + ");\n"
423             + "      log(row.cells.length);\n"
424             + "      log(newCell.cellIndex);\n"
425             + "    } catch(e) { logEx(e); }\n"
426             + "  </script>\n"
427             + "</body></html>";
428 
429         loadPageVerifyTitle2(html);
430     }
431 
432     /**
433      * @throws Exception if the test fails
434      */
435     @Test
436     @Alerts({"2", "3", "2"})
437     public void insertCellEmpty() throws Exception {
438         insertCell("");
439     }
440 
441     /**
442      * @throws Exception if the test fails
443      */
444     @Test
445     @Alerts({"2", "IndexSizeError/DOMException"})
446     public void insertCell_MinusTwo() throws Exception {
447         insertCell("-2");
448     }
449 
450     /**
451      * @throws Exception if the test fails
452      */
453     @Test
454     @Alerts({"2", "3", "2"})
455     public void insertCell_MinusOne() throws Exception {
456         insertCell("-1");
457     }
458 
459     /**
460      * @throws Exception if the test fails
461      */
462     @Test
463     @Alerts({"2", "3", "0"})
464     public void insertCell_Zero() throws Exception {
465         insertCell("0");
466     }
467 
468     /**
469      * @throws Exception if the test fails
470      */
471     @Test
472     @Alerts({"2", "3", "1"})
473     public void insertCell_One() throws Exception {
474         insertCell("1");
475     }
476 
477     /**
478      * @throws Exception if the test fails
479      */
480     @Test
481     @Alerts({"2", "3", "2"})
482     public void insertCell_Two() throws Exception {
483         insertCell("2");
484     }
485 
486     /**
487      * @throws Exception if the test fails
488      */
489     @Test
490     @Alerts({"2", "IndexSizeError/DOMException"})
491     public void insertCell_Three() throws Exception {
492         insertCell("3");
493     }
494 
495     /**
496      * @throws Exception if the test fails
497      */
498     @Test
499     @Alerts({"undefined", "#667788", "unknown", "undefined", "undefined", "undefined"})
500     public void borderColor() throws Exception {
501         final String html = DOCTYPE_HTML
502             + "<html><body>\n"
503             + "  <table><tr id='tabr1'></tr></table>\n"
504             + "  <table><tr id='tabr2' borderColor='red'></tr></table>\n"
505             + "  <table><tr id='tabr3' borderColor='#123456'></tr></table>\n"
506             + "  <table><tr id='tabr4' borderColor='unknown'></tr></table>\n"
507             + "<script>\n"
508             + LOG_TITLE_FUNCTION
509             + "  var node = document.getElementById('tabr1');\n"
510             + "  log(node.borderColor);\n"
511 
512             + "  node.borderColor = '#667788';\n"
513             + "  log(node.borderColor);\n"
514 
515             + "  node.borderColor = 'unknown';\n"
516             + "  log(node.borderColor);\n"
517 
518             + "  var node = document.getElementById('tabr2');\n"
519             + "  log(node.borderColor);\n"
520             + "  var node = document.getElementById('tabr3');\n"
521             + "  log(node.borderColor);\n"
522             + "  var node = document.getElementById('tabr4');\n"
523             + "  log(node.borderColor);\n"
524 
525             + "</script></body></html>";
526 
527         loadPageVerifyTitle2(html);
528     }
529 
530     /**
531      * @throws Exception if the test fails
532      */
533     @Test
534     @Alerts({"undefined", "undefined", "undefined", "undefined", "undefined", "undefined"})
535     public void borderColorDark() throws Exception {
536         final String html = DOCTYPE_HTML
537             + "<html><body>\n"
538             + "  <table><tr id='tabr1'></tr></table>\n"
539             + "  <table><tr id='tabr2' borderColorDark='red'></tr></table>\n"
540             + "  <table><tr id='tabr3' borderColorDark='#123456'></tr></table>\n"
541             + "  <table><tr id='tabr4' borderColorDark='unknown'></tr></table>\n"
542             + "<script>\n"
543             + LOG_TITLE_FUNCTION
544             + "  var node = document.getElementById('tabr1');\n"
545             + "  log(node.borderColorDark);\n"
546 
547             + "  node.borderColor = '#667788';\n"
548             + "  log(node.borderColorDark);\n"
549 
550             + "  node.borderColor = 'unknown';\n"
551             + "  log(node.borderColorDark);\n"
552 
553             + "  var node = document.getElementById('tabr2');\n"
554             + "  log(node.borderColorDark);\n"
555             + "  var node = document.getElementById('tabr3');\n"
556             + "  log(node.borderColorDark);\n"
557             + "  var node = document.getElementById('tabr4');\n"
558             + "  log(node.borderColorDark);\n"
559 
560             + "</script></body></html>";
561         loadPageVerifyTitle2(html);
562     }
563 
564     /**
565      * @throws Exception if the test fails
566      */
567     @Test
568     @Alerts({"undefined", "undefined", "undefined", "undefined", "undefined", "undefined"})
569     public void borderColorLight() throws Exception {
570         final String html = DOCTYPE_HTML
571             + "<html><body>\n"
572             + "  <table><tr id='tabr1'></tr></table>\n"
573             + "  <table><tr id='tabr2' borderColorLight='red'></tr></table>\n"
574             + "  <table><tr id='tabr3' borderColorLight='#123456'></tr></table>\n"
575             + "  <table><tr id='tabr4' borderColorLight='unknown'></tr></table>\n"
576             + "<script>\n"
577             + LOG_TITLE_FUNCTION
578             + "  var node = document.getElementById('tabr1');\n"
579             + "  log(node.borderColorLight);\n"
580 
581             + "  node.borderColor = '#667788';\n"
582             + "  log(node.borderColorLight);\n"
583 
584             + "  node.borderColor = 'unknown';\n"
585             + "  log(node.borderColorLight);\n"
586 
587             + "  var node = document.getElementById('tabr2');\n"
588             + "  log(node.borderColorLight);\n"
589             + "  var node = document.getElementById('tabr3');\n"
590             + "  log(node.borderColorLight);\n"
591             + "  var node = document.getElementById('tabr4');\n"
592             + "  log(node.borderColorLight);\n"
593 
594             + "</script></body></html>";
595 
596         loadPageVerifyTitle2(html);
597     }
598 
599     /**
600      * @throws Exception if an error occurs
601      */
602     @Test
603     @Alerts({"true", "true"})
604     public void heightIsMaxOfCells() throws Exception {
605         final String html = DOCTYPE_HTML
606             + "<html><body>\n"
607             + "<table>\n"
608             + "  <tr id='tr1'>\n"
609             + "    <td style='height: 30px'>a</td>\n"
610             + "    <td style='height: 10px'>b</td>\n"
611             + "    <td style='height: 40px'>d</td>\n"
612             + "  </tr>\n"
613             + "</table>\n"
614 
615             + "<script>\n"
616             + LOG_TITLE_FUNCTION
617             + "  var tr1 = document.getElementById('tr1');\n"
618             + "  log(tr1.offsetHeight > 35);\n"
619             + "  log(tr1.offsetHeight < 45);\n"
620             + "</script>\n"
621             + "</body></html>";
622 
623         loadPageVerifyTitle2(html);
624     }
625 }