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