Upstream version 10.38.222.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / chromeos / chromevox / common / dom_util_test.js
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Include test fixture.
6 GEN_INCLUDE(['../testing/chromevox_unittest_base.js']);
7
8 /**
9  * Test fixture.
10  * @constructor
11  * @extends {ChromeVoxUnitTestBase}
12  */
13 function CvoxDomUtilUnitTest() {}
14
15 CvoxDomUtilUnitTest.prototype = {
16   __proto__: ChromeVoxUnitTestBase.prototype,
17
18   /** @override */
19   closureModuleDeps: [
20     'cvox.ChromeVox',
21     'cvox.DescriptionUtil',
22     'cvox.DomUtil',
23     'cvox.TestMsgs',
24   ],
25
26   /** @override */
27   setUp: function() {
28     cvox.ChromeVox.msgs = new cvox.TestMsgs();
29   },
30
31   asText_: function(node) {
32     var temp = document.createElement('div');
33     temp.appendChild(node);
34     return temp.innerHTML;
35   },
36
37   assertEqualsAsText_: function(node1, node2) {
38     assertEquals(this.asText_(node1), this.asText_(node2));
39   },
40
41   loadDomUtilTestDoc_: function() {
42     this.loadDoc(function() {/*!
43     <style type="text/css">
44       #display_none { display: none; }
45       #visibility_hidden { visibility: hidden; }
46       #forced_visible { visibility: hidden; }
47       #visibility_collapse { visibility: collapse; }
48       #opacity_zero { opacity: 0; }
49       #opacity_partial { opacity: 0.5; }
50       #opacity_undefined { }
51       #nested_visibility_hide { visibility: hidden; }
52       #nested_visibility_show { visibility: visible; }
53       #nested_display_none { display: none; }
54       #nested_display_block { display: block; }
55     </style>
56    <form action="">
57
58     <div id="normal_node">1</div>
59     <div id="display_none">2</div>
60     <div id="visibility_hidden">3</div>
61     <div id="visibility_collapse">3b</div>
62     <div id="opacity_zero">4</div>
63     <div id="opacity_partial">4b</div>
64     <div id="opacity_undefined">5</div>
65     <select id="select_node"><option>5</option></select>
66     <textarea id="textarea">6</textarea>
67     <div id="forced_visible" aria-hidden="false">7</div>
68     <p id="normal_para">----</p>
69     <p id="presentation" role="presentation">----</p>
70     <p id="aria_hidden" aria-hidden="true">----</p>
71     <p id="only_spaces">    </p>
72     <p id="only_tabs">        </p>
73     <p id="only_newlines">
74
75     </p>
76     <p id="only_nbsp">&nbsp;</p>
77     <p id="other_entity">&amp;</p>
78     <img id="img">
79     <img id="img_alt" alt="tree">
80     <img id="img_blankalt" alt="">
81
82     <input id="check" type="checkbox">
83     <input id="check_checked" type="checkbox" checked>
84
85     <span><p id="a">a</p></span>
86     <span><p id="b">b</p><p id="c">c</p></span>
87     </form>
88
89     <a id="special_link1" href="http://google.com"><span id="empty_span"></span>
90     </a>
91     <a id="special_link2" href="http://google.com"><span>Text content</span></a>
92     <a id="special_link3"><span></span></a>
93
94     <div id="nested_visibility_hide">
95       hide<div id="nested_visibility_show">show</div>me
96     </div>
97     <div id="nested_display_none">
98       nothing<div id="nested_display_block">will</div>show
99     </div>
100     */});
101   },
102 };
103
104 TEST_F('CvoxDomUtilUnitTest', 'IsVisible', function() {
105   this.loadDomUtilTestDoc_();
106
107   // Simple tests.
108   var node = $('normal_node');
109   assertEquals(true, cvox.DomUtil.isVisible(node));
110   node = $('display_none');
111   assertEquals(false, cvox.DomUtil.isVisible(node));
112   node = $('visibility_hidden');
113   assertEquals(false, cvox.DomUtil.isVisible(node));
114   node = $('visibility_collapse');
115   assertEquals(false, cvox.DomUtil.isVisible(node));
116   node = $('opacity_zero');
117   assertEquals(false, cvox.DomUtil.isVisible(node));
118   node = $('opacity_partial');
119   assertEquals(true, cvox.DomUtil.isVisible(node));
120   node = $('opacity_undefined');
121   assertEquals(true, cvox.DomUtil.isVisible(node));
122   node = $('forced_visible');
123   assertEquals(true, cvox.DomUtil.isVisible(node));
124
125   // Nested visibility tests.
126   node = $('nested_visibility_hide');
127   assertEquals(true, cvox.DomUtil.isVisible(node)); // Has visible child.
128   node = $('nested_visibility_hide').childNodes[0];
129   assertEquals(false, cvox.DomUtil.isVisible(node)); // TextNode is invisible.
130   node = $('nested_visibility_show');
131   assertEquals(true, cvox.DomUtil.isVisible(node));
132   node = $('nested_visibility_show').childNodes[0];
133   assertEquals(true, cvox.DomUtil.isVisible(node)); // TextNode is visible.
134   node = $('nested_display_block');
135   assertEquals(false, cvox.DomUtil.isVisible(node));
136
137   // Options tests (for performance).
138   node = $('nested_display_block');
139   assertEquals(true,
140       cvox.DomUtil.isVisible(node, {checkAncestors: false}));
141   node = $('nested_visibility_hide');
142   assertEquals(false,
143       cvox.DomUtil.isVisible(node, {checkDescendants: false}));
144 });
145
146 /** Test determining if a node is a leaf node or not. @export */
147 TEST_F('CvoxDomUtilUnitTest', 'IsLeafNode', function() {
148   this.loadDomUtilTestDoc_();
149
150   var node = $('normal_node');
151   assertEquals(false, cvox.DomUtil.isLeafNode(node));
152   node = $('display_none');
153   assertEquals(true, cvox.DomUtil.isLeafNode(node));
154   node = $('visibility_hidden');
155   assertEquals(true, cvox.DomUtil.isLeafNode(node));
156   node = $('opacity_zero');
157   assertEquals(true, cvox.DomUtil.isLeafNode(node));
158   node = $('select_node');
159   assertEquals(true, cvox.DomUtil.isLeafNode(node));
160   node = $('textarea');
161   assertEquals(true, cvox.DomUtil.isLeafNode(node));
162   node = $('normal_para');
163   assertEquals(false, cvox.DomUtil.isLeafNode(node));
164   node = $('aria_hidden');
165   assertEquals(true, cvox.DomUtil.isLeafNode(node));
166   node = $('special_link1');
167   assertEquals(true, cvox.DomUtil.isLeafNode(node));
168   node = $('special_link2');
169   assertEquals(true, cvox.DomUtil.isLeafNode(node));
170   node = $('special_link3');
171   assertEquals(false, cvox.DomUtil.isLeafNode(node));
172   node = $('nested_visibility_hide');
173   assertEquals(false, cvox.DomUtil.isLeafNode(node));
174 });
175
176 /** Test determining if a node has content or not. @export */
177 TEST_F('CvoxDomUtilUnitTest', 'HasContent', function() {
178   this.loadDomUtilTestDoc_();
179
180   var node = $('normal_node');
181   cvox.DomUtil.hasContent(node);
182   assertEquals(true, cvox.DomUtil.hasContent(node));
183   node = $('display_none');
184   assertEquals(false, cvox.DomUtil.hasContent(node));
185   node = $('visibility_hidden');
186   assertEquals(false, cvox.DomUtil.hasContent(node));
187   node = $('opacity_zero');
188   assertEquals(false, cvox.DomUtil.hasContent(node));
189   node = $('select_node');
190   assertEquals(true, cvox.DomUtil.hasContent(node));
191   node = $('textarea');
192   assertEquals(true, cvox.DomUtil.hasContent(node));
193   node = $('normal_para');
194   assertEquals(true, cvox.DomUtil.hasContent(node));
195   // TODO (adu): This test fails. Will inspect.
196   // node = $('presentation');
197   // assertEquals(false, cvox.DomUtil.hasContent(node));
198   node = $('aria_hidden');
199   assertEquals(false, cvox.DomUtil.hasContent(node));
200   node = $('only_spaces');
201   assertEquals(false, cvox.DomUtil.hasContent(node));
202   node = $('only_tabs');
203   assertEquals(false, cvox.DomUtil.hasContent(node));
204   node = $('only_newlines');
205   assertEquals(false, cvox.DomUtil.hasContent(node));
206   node = $('other_entity');
207   assertEquals(true, cvox.DomUtil.hasContent(node));
208   node = $('img');
209   assertEquals(true, cvox.DomUtil.hasContent(node));
210   node = $('img_alt');
211   assertEquals(true, cvox.DomUtil.hasContent(node));
212   node = $('img_blankalt');
213   assertEquals(false, cvox.DomUtil.hasContent(node));
214 });
215
216 /** Test getting a node's state. @export */
217 TEST_F('CvoxDomUtilUnitTest', 'NodeState', function() {
218   this.loadDomUtilTestDoc_();
219   this.appendDoc(function() {/*!
220   <input id="state1_enabled">
221   <input id="state1_disabled" disabled>
222   <button id="state2_enabled">Button</button>
223   <button id="state2_disabled" disabled>Button</button>
224   <textarea id="state3_enabled">Textarea</textarea>
225   <textarea id="state3_disabled" disabled>Textarea</textarea>
226   <select id="state4_enabled"><option>Select</option></select>
227   <select id="state4_disabled" disabled><option>Select</option></select>
228   <div role="button" id="state5_enabled" tabindex="0">ARIAButton</div>
229   <div role="button" id="state5_disabled" tabindex="0" disabled>ARIAButton</div>
230   <fieldset>
231     <input id="state6_enabled">
232   </fieldset>
233   <fieldset disabled>
234     <input id="state6_disabled">
235   </fieldset>
236   */});
237   var node = $('check');
238   assertEquals('not checked', cvox.DomUtil.getState(node, true));
239   node = $('check_checked');
240   assertEquals('checked', cvox.DomUtil.getState(node, true));
241   node = $('state1_enabled');
242   assertEquals('', cvox.DomUtil.getState(node, true));
243   node = $('state1_disabled');
244   assertEquals('Disabled', cvox.DomUtil.getState(node, true));
245   node = $('state2_enabled');
246   assertEquals('', cvox.DomUtil.getState(node, true));
247   node = $('state2_disabled');
248   assertEquals('Disabled', cvox.DomUtil.getState(node, true));
249   node = $('state3_enabled');
250   assertEquals('', cvox.DomUtil.getState(node, true));
251   node = $('state3_disabled');
252   assertEquals('Disabled', cvox.DomUtil.getState(node, true));
253   node = $('state4_enabled');
254   assertEquals('1 of 1', cvox.DomUtil.getState(node, true));
255   node = $('state4_disabled');
256   assertEquals('1 of 1 Disabled', cvox.DomUtil.getState(node, true));
257   node = $('state5_enabled');
258   assertEquals('', cvox.DomUtil.getState(node, true));
259   node = $('state5_disabled');
260   assertEquals('', cvox.DomUtil.getState(node, true));
261   node = $('state6_enabled');
262   assertEquals('', cvox.DomUtil.getState(node, true));
263   node = $('state6_disabled');
264   assertEquals('Disabled', cvox.DomUtil.getState(node, true));
265 });
266
267 /** Test finding the next/previous leaf node. @export */
268 TEST_F('CvoxDomUtilUnitTest', 'LeafNodeTraversal', function() {
269   this.loadDomUtilTestDoc_();
270
271   var node = $('a');
272   node = cvox.DomUtil.directedNextLeafNode(node);
273   assertEquals('\n    ', node.textContent);
274   node = cvox.DomUtil.directedNextLeafNode(node);
275   assertEquals('b', node.textContent);
276   node = cvox.DomUtil.directedNextLeafNode(node);
277   assertEquals('c', node.textContent);
278   node = cvox.DomUtil.previousLeafNode(node);
279   assertEquals('b', node.textContent);
280   node = cvox.DomUtil.previousLeafNode(node);
281   assertEquals('\n    ', node.textContent);
282   node = cvox.DomUtil.previousLeafNode(node);
283   assertEquals('a', node.textContent);
284 });
285
286 /** Test finding the label for controls. @export */
287 TEST_F('CvoxDomUtilUnitTest', 'GetLabel', function() {
288   this.loadDoc(function() {/*!
289     <fieldset id="Fieldset">
290     <legend>This is a legend inside a fieldset</legend>
291     <div align="right">
292     <span>
293     Username:
294     </span>
295     </div>
296     <input name="Email" id="Email" size="18" value="" type="text">
297     <span>
298     Password:
299     </span>
300     <input name="Passwd" id="Passwd" size="18" type="password">
301     <input name="PersistentCookie" id="PersistentCookie" type="checkbox">
302     <label for="PersistentCookie" id="PersistentCookieLabel">
303     Stay signed in
304     </label>
305     <input name="signIn" id="signIn" value="Sign in" type="submit">
306     <input id="dummyA" size="18" value="" type="text" title="">
307     <input id="dummyB" size="18" value="" type="text" aria-label="">
308     </fieldset>
309   */});
310
311   function getControlText(control) {
312     var description = cvox.DescriptionUtil.getControlDescription(control);
313     return cvox.DomUtil.collapseWhitespace(
314         description.context + ' ' +
315         description.text + ' ' +
316         description.userValue + ' ' +
317         description.annotation);
318   }
319
320   var fieldsetElement = $('Fieldset');
321   assertEquals('This is a legend inside a fieldset',
322       cvox.DomUtil.getName(fieldsetElement, false, false));
323
324   var usernameField = $('Email');
325   assertEquals('', cvox.DomUtil.getValue(usernameField));
326   assertEquals('Username:',
327       cvox.DomUtil.getControlLabelHeuristics(usernameField));
328   assertEquals('Username: Edit text', getControlText(usernameField));
329   var passwordField = $('Passwd');
330   assertEquals('', cvox.DomUtil.getValue(passwordField));
331   assertEquals('Password:',
332       cvox.DomUtil.getControlLabelHeuristics(passwordField));
333   assertEquals('Password: Password edit text', getControlText(passwordField));
334   var cookieCheckbox = $('PersistentCookie');
335   assertEquals('Stay signed in', cvox.DomUtil.getName(cookieCheckbox));
336   assertEquals('Stay signed in Check box not checked',
337       getControlText(cookieCheckbox));
338   var signinButton = $('signIn');
339   assertEquals('Sign in', cvox.DomUtil.getName(signinButton));
340   assertEquals('Sign in Button', getControlText(signinButton));
341   var dummyInputA = $('dummyA');
342   assertEquals('', cvox.DomUtil.getName(dummyInputA));
343   var dummyInputB = $('dummyB');
344   assertEquals('', cvox.DomUtil.getName(dummyInputB));
345
346   // The heuristic no longer returns 'Stay signed in' as the label for
347   // the signIn button because 'Stay signed in' is in a label that's
348   // explicitly associated with another control.
349   //assertEquals('Stay signed in ',
350   //    cvox.DomUtil.getControlLabelHeuristics(signinButton));
351 });
352
353 /** Test finding the label for controls with a more complex setup. @export */
354 TEST_F('CvoxDomUtilUnitTest', 'GetLabelComplex', function() {
355   this.loadDoc(function() {/*!
356   <table class="bug-report-table">
357   <tbody><tr>
358   <td class="bug-report-fieldlabel">
359   <input id="page-url-checkbox" type="checkbox">
360   <span id="page-url-label" i18n-content="page-url">Include this URL:</span>
361   </td>
362   <td>
363   <input id="page-url-text" class="bug-report-field" maxlength="200">
364   </td>
365   </tr>
366   </tbody></table>
367   <table id="user-email-table" class="bug-report-table">
368   <tbody><tr>
369   <td class="bug-report-fieldlabel">
370   <input id="user-email-checkbox" checked="checked" type="checkbox">
371   <span id="user-email-label">Include this email:</span>
372   </td>
373   <td>
374   <label id="user-email-text" class="bug-report-field"></label>
375   </td>
376   </tr>
377   </tbody></table>
378   <table class="bug-report-table">
379   <tbody><tr>
380   <td class="bug-report-fieldlabel">
381   <input id="sys-info-checkbox" checked="checked" type="checkbox">
382   <span id="sysinfo-label">
383   <a id="sysinfo-url" href="#">Send system information</a>
384   </span>
385   </td>
386   </tr>
387   </tbody></table>
388   <table class="bug-report-table">
389   <tbody><tr>
390   <td class="bug-report-fieldlabel">
391   <input id="screenshot-checkbox" type="checkbox">
392   <span id="screenshot-label-current">Include the current screenshot:</span>
393   </td>
394   </tr>
395   </tbody></table>
396   */});
397   var urlCheckbox = $('page-url-checkbox');
398   assertEquals('Include this URL:',
399       cvox.DomUtil.getControlLabelHeuristics(urlCheckbox));
400   var emailCheckbox = $('user-email-checkbox');
401   assertEquals('Include this email:',
402       cvox.DomUtil.getControlLabelHeuristics(emailCheckbox));
403   var sysCheckbox = $('sys-info-checkbox');
404   assertEquals('Send system information',
405       cvox.DomUtil.getControlLabelHeuristics(sysCheckbox));
406 });
407
408 /**************************************************************/
409
410 TEST_F('CvoxDomUtilUnitTest', 'EscapedNames', function() {
411   this.loadDoc(function() {/*!
412      <p id="en-title" title="&lt;&gt;"></p>
413      <p id="en-arialabel" aria-label="&lt;&gt;"></p>
414      <img id="en-img" title="&lt;&gt;"></img>
415      <p id="en-double" title="&amp;lt;&amp;gt;"></p>
416      */});
417   assertEquals('<>', cvox.DomUtil.getName(
418       $('en-title')));
419   assertEquals('<>', cvox.DomUtil.getName(
420       $('en-arialabel')));
421   assertEquals('<>', cvox.DomUtil.getName(
422       $('en-img')));
423   assertEquals('&lt;&gt;', cvox.DomUtil.getName(
424       $('en-double')));
425 });
426
427 /** Test a paragraph with plain text. @export */
428 TEST_F('CvoxDomUtilUnitTest', 'SimplePara', function() {
429   this.loadDoc(function() {/*!
430     <p id="simplepara">This is a simple paragraph.</p>
431   */});
432   var node = $('simplepara');
433   var text = cvox.DomUtil.collapseWhitespace(cvox.DomUtil.getName(node));
434   assertEquals('This is a simple paragraph.', text);
435 });
436
437 /** Test a paragraph with nested tags. @export */
438 TEST_F('CvoxDomUtilUnitTest', 'NestedPara', function() {
439   this.loadDoc(function() {/*!
440     <p id="nestedpara">This is a <b>paragraph</b> with <i>nested</i> tags.</p>
441   */});
442   var node = $('nestedpara');
443   var text = cvox.DomUtil.collapseWhitespace(cvox.DomUtil.getName(node));
444   assertEquals('This is a paragraph with nested tags.', text);
445 });
446
447 /**
448  * Test a paragraph with nested tags and varying visibility.
449  * @export
450  */
451 TEST_F('CvoxDomUtilUnitTest', 'NestedVisibilityPara', function() {
452   this.loadDoc(function() {/*!
453     <style type="text/css">
454       #nested_visibility_paragraph { }
455       #nested_visibility_paragraph .hide { visibility: hidden; }
456       #nested_visibility_paragraph .show { visibility: visible; }
457     </style>
458     <p id="nested_visibility_paragraph">
459       This is
460       <span class="hide">
461         not
462         <span class="show"> a sentence.</span>
463       </span>
464     </p>
465   */});
466   var node = $('nested_visibility_paragraph');
467   var text = cvox.DomUtil.collapseWhitespace(cvox.DomUtil.getName(node));
468   assertEquals('This is a sentence.', text);
469 });
470
471 /** Test getting text from an IMG node. @export */
472 TEST_F('CvoxDomUtilUnitTest', 'Image', function() {
473   this.loadDoc(function() {/*!
474     <img id="img">
475     <img id="img_noalt" src="rose.png">
476     <img id="img_alt" alt="flower" src="rose.png">
477     <img id="img_title" title="a Flower" src="rose.png">
478     <img id="img_noalt_long"
479          src="777777777777777777777777777777777.png">
480   */});
481
482   var node = $('img');
483   assertEquals('Image', cvox.DomUtil.getName(node));
484   node = $('img_noalt');
485   assertEquals('rose Image', cvox.DomUtil.getName(node));
486   node = $('img_alt');
487   assertEquals('flower', cvox.DomUtil.getName(node));
488   node = $('img_title');
489   assertEquals('a Flower', cvox.DomUtil.getName(node));
490   node = $('img_noalt_long');
491   assertEquals('Image', cvox.DomUtil.getName(node));
492 });
493
494 /** Test getting text from a select box. @export */
495 TEST_F('CvoxDomUtilUnitTest', 'Select', function() {
496   this.loadDoc(function() {/*!
497     <select id="select_noneselected">
498       <option>Apple</option>
499       <option>Banana</option>
500       <option>Pear</option>
501     </select>
502     <select id="select_bananaselected">
503       <option>Apple</option>
504       <option selected>Banana</option>
505       <option>Pear</option>
506     </select>
507   */});
508
509   $('select_noneselected').selectedIndex = -1;
510   var node = $('select_noneselected');
511   assertEquals('', cvox.DomUtil.getValue(node));
512   node = $('select_bananaselected');
513   assertEquals('Banana', cvox.DomUtil.getValue(node));
514 });
515
516 /** Test whether funky html causes getName to go into infinite loop. */
517 TEST_F('CvoxDomUtilUnitTest', 'GetNameInfiniteLoop', function() {
518   this.loadDoc(function() {/*!
519     <div>
520       <label for="a">
521         <p id="a">asdf</p>
522       </label>
523     </div>
524   */});
525   // intentionally no asserts; if there is an infinite (recursive) loop,
526   // the stack will blow up
527   var node = $('a');
528   var label = cvox.DomUtil.getName(node);
529 });
530
531 /** Test getting text from an INPUT control. @export */
532 TEST_F('CvoxDomUtilUnitTest', 'Input', function() {
533   this.loadDoc(function() {/*!
534     <form action="">
535       <input id="hidden" type="hidden" value="hidden1">
536       <input id="input_img" type="image" src="rose.png">
537       <input id="input_img_alt" type="image" alt="flower" src="rose.png">
538       <input id="submit" type="submit">
539       <input id="submit_withvalue" type="submit" value="Go">
540       <input id="reset" type="reset">
541       <input id="reset_withvalue" type="reset" value="Stop">
542       <input id="button" type="button" value="Button">
543       <input id="checkbox" type="checkbox" value="ignore1">
544       <input id="checkbox_title" type="checkbox" value="ignore1" title="toggle">
545       <input id="radio" type="radio" value="ignore2">
546       <input id="password" type="password" value="dragon">
547       <input id="text" value="my text">
548       <input id="placeholder0" placeholder="Phone number">
549       <input id="placeholder1" title="Phone number">
550       <input id="placeholder2" title="Phone number" placeholder="xxx-yyy-zzzz">
551       <input id="placeholder3" title="Phone number" placeholder="xxx-yyy-zzzz"
552                                value="310-555-1212">
553     </form>
554   */});
555
556   var node = $('hidden');
557   assertEquals('', cvox.DomUtil.getName(node));
558   node = $('input_img');
559   assertEquals('rose Image', cvox.DomUtil.getName(node));
560   node = $('input_img_alt');
561   assertEquals('flower', cvox.DomUtil.getName(node));
562   node = $('submit');
563   assertEquals('Submit', cvox.DomUtil.getName(node));
564   node = $('submit_withvalue');
565   assertEquals('Go', cvox.DomUtil.getName(node));
566   node = $('reset');
567   assertEquals('Reset', cvox.DomUtil.getName(node));
568   node = $('reset_withvalue');
569   assertEquals('Stop', cvox.DomUtil.getName(node));
570   node = $('button');
571   assertEquals('Button', cvox.DomUtil.getName(node));
572   node = $('checkbox');
573   assertEquals('', cvox.DomUtil.getName(node));
574   node = $('checkbox_title');
575   assertEquals('toggle', cvox.DomUtil.getName(node));
576   node = $('radio');
577   assertEquals('', cvox.DomUtil.getName(node));
578   node = $('password');
579   assertEquals('dot dot dot dot dot dot ', cvox.DomUtil.getValue(node));
580   node = $('text');
581   assertEquals('my text', cvox.DomUtil.getValue(node));
582   node = $('placeholder0');
583   assertEquals('Phone number', cvox.DomUtil.getName(node));
584   node = $('placeholder1');
585   assertEquals('Phone number', cvox.DomUtil.getName(node));
586   node = $('placeholder2');
587   assertEquals('xxx-yyy-zzzz',
588                cvox.DomUtil.getName(node));
589   node = $('placeholder3');
590   assertEquals('310-555-1212 xxx-yyy-zzzz',
591                cvox.DomUtil.getValue(node) + ' ' + cvox.DomUtil.getName(node));
592 });
593
594
595 /** Test checking if something is a control. @export */
596 TEST_F('CvoxDomUtilUnitTest', 'IsControl', function() {
597   this.loadDoc(function() {/*!
598   <table width="100%" border="0" cellpadding="0" cellspacing="0">
599     <tbody>
600       <tr>
601         <td>&nbsp;</td>
602
603         <td nowrap="nowrap">
604           <table width="100%" border="0" cellpadding="0" cellspacing="0">
605             <tbody>
606               <tr>
607                 <td bgcolor="#3366CC"><img alt="" width="1" height="1"></td>
608               </tr>
609             </tbody>
610           </table>
611
612           <table width="100%" border="0" cellpadding="0" cellspacing="0">
613             <tbody>
614               <tr>
615                 <td bgcolor="#E5ECF9" nowrap="nowrap"><font color="#000000"
616                 face="arial,sans-serif" size="+1"><b>&nbsp;Preferences</b>
617                 </font></td>
618
619                 <td align="right" bgcolor="#E5ECF9" nowrap="nowrap">
620                 <font color="#000000" face="arial,sans-serif" size="-1">
621                 <a href="http://www.google.com/accounts/ManageAccount">Google
622                 Account settings</a> | <a href="http://www.google.com/">
623                 Preferences Help</a> | <a href="/about.html">About
624                 Google</a>&nbsp;</font></td>
625               </tr>
626             </tbody>
627           </table>
628         </td>
629       </tr>
630     </tbody>
631   </table>
632
633   <table width="100%" border="0" cellpadding="2" cellspacing="0">
634     <tbody>
635       <tr bgcolor="#E5ECF9">
636         <td><font face="arial,sans-serif" size="-1"><b>Save</b> your
637         preferences when finished and <b>return to search</b>.</font></td>
638
639         <td align="right"><font face="arial,sans-serif" size="-1">
640         <input value="Save Preferences " name="submit2" type="submit">
641         </font></td>
642       </tr>
643     </tbody>
644   </table>
645
646   <h1>Global Preferences</h1><font size="-1">(changes apply to all Google
647   services)</font><br>
648
649   <table width="100%" border="0" cellpadding="0" cellspacing="0">
650     <tbody>
651       <tr>
652         <td bgcolor="#CBDCED"><img alt="" width="1" height="2"></td>
653       </tr>
654     </tbody>
655   </table>
656
657   <table width="100%" border="0" cellpadding="0" cellspacing="0">
658     <tbody>
659       <tr>
660         <td width="1" bgcolor="#CBDCED"><img alt="" width="2" height="1"></td>
661
662         <td valign="top" width="175" nowrap="nowrap">
663           &nbsp;<br>
664           &nbsp;
665
666           <h2>Interface Language</h2>
667         </td>
668
669         <td colspan="2"><br>
670         <font face="arial,sans-serif" size="-1">Display Google tips and
671         messages in: <select name="hl">
672           <option value="af">
673             Afrikaans
674           </option>
675
676           <option value="ak">
677             Akan
678           </option>
679
680           <option value="sq">
681             Albanian
682           </option>
683
684           <option value="am">
685             Amharic
686           </option>
687
688           <option value="ar">
689             Arabic
690           </option>
691         </select><br>
692         If you do not find your native language in the pulldown above, you
693         can<br>
694         help Google create it through our
695         <a href="http://services.google.com/">Google in Your Language
696         program</a>.<br>
697         &nbsp;</font></td>
698       </tr>
699     </tbody>
700   </table>
701
702   <table width="100%" border="0" cellpadding="0" cellspacing="0">
703     <tbody>
704       <tr>
705         <td colspan="4" bgcolor="#CBDCED"><img alt="" width="1" height="1"></td>
706       </tr>
707
708       <tr>
709         <td width="1" bgcolor="#CBDCED"><img alt="" width="2" height="1"></td>
710
711         <td valign="top" width="175" nowrap="nowrap">
712           &nbsp;<br>
713           &nbsp;
714
715           <h2>Search Language</h2>
716         </td>
717
718         <td>
719           &nbsp;<br>
720           <font face="arial,sans-serif" size="-1">Prefer pages written in these
721           language(s):</font><br>
722
723           <table border="0" cellpadding="5" cellspacing="10">
724             <tbody>
725               <tr>
726                 <td valign="top" nowrap="nowrap"><font face="arial,sans-serif"
727                 size="-1"><label><input name="lr" value="lang_af"
728                 onclick="tick()" id="paf" type="checkbox">
729                 <span id="taf">Afrikaans</span></label><br>
730                 <label><input name="lr" value="lang_ar" onclick="tick()"
731                 id="par" type="checkbox"> <span id="tar">Arabic</span></label>
732                 <br>
733                 <label><input name="lr" value="lang_hy" onclick="tick()"
734                 id="phy" type="checkbox"> <span id="thy">Armenian</span>
735                 </label><br>
736                 <label><input name="lr" value="lang_be" onclick="tick()"
737                 id="pbe" type="checkbox"> <span id="tbe">Belarusian</span>
738                 </label><br>
739                 <label><input name="lr" value="lang_bg" onclick="tick()"
740                 id="pbg" type="checkbox"> <span id="tbg">Bulgarian</span>
741                 </label><br>
742                 <label><input name="lr" value="lang_ca" onclick="tick()"
743                 id="pca" type="checkbox"> <span id="tca">Catalan</span>
744                 </label><br>
745                 <label><input name="lr" value="lang_zh-CN" onclick="tick()"
746                 id="pzh-CN" type="checkbox"> <span id="tzh-CN">
747                 Chinese&nbsp;(Simplified)</span></label><br>
748                 <label><input name="lr" value="lang_zh-TW" onclick="tick()"
749                 id="pzh-TW" type="checkbox"> <span id="tzh-TW">
750                 Chinese&nbsp;(Traditional)</span></label><br>
751                 <label><input name="lr" value="lang_hr" onclick="tick()"
752                 id="phr" type="checkbox"> <span id="thr">Croatian</span>
753                 </label><br>
754                 <label><input name="lr" value="lang_cs" onclick="tick()"
755                 id="pcs" type="checkbox"> <span id="tcs">Czech</span>
756                 </label><br>
757                 <label><input name="lr" value="lang_da" onclick="tick()"
758                 id="pda" type="checkbox"> <span id="tda">Danish</span>
759                 </label><br>
760                 <label><input name="lr" value="lang_nl" onclick="tick()"
761                 id="pnl" type="checkbox"> <span id="tnl">Dutch</span>
762                 </label></font></td>
763               </tr>
764             </tbody>
765           </table>
766         </td>
767       </tr>
768     </tbody>
769   </table><a name="loc" id="loc"></a>
770
771   <table width="100%" border="0" cellpadding="0" cellspacing="0">
772     <tbody>
773       <tr>
774         <td colspan="4" bgcolor="#CBDCED"><img alt="" width="1" height="1"></td>
775       </tr>
776
777       <tr>
778         <td width="1" bgcolor="#CBDCED"><img alt="" width="2" height="1"></td>
779
780         <td valign="top" width="175" nowrap="nowrap">
781           &nbsp;<br>
782           &nbsp;
783
784           <h2>Location</h2>
785         </td>
786
787         <td>
788           <br>
789
790           <div style="color: rgb(204, 0, 0); display: none;" id="locerr">
791             <span id="lem"><font face="arial,sans-serif" size="-1">The location
792             <b>X</b> was not recognized.</font></span>
793             <font face="arial,sans-serif" size="-1"><br>
794             <br>
795             Suggestions:<br></font>
796
797             <ul>
798               <li><font face="arial,sans-serif" size="-1">Make sure all street
799               and city names are spelled correctly.</font></li>
800
801               <li><font face="arial,sans-serif" size="-1">Make sure the address
802               included a city and state.</font></li>
803
804               <li><font face="arial,sans-serif" size="-1">Try entering a Zip
805               code.</font></li>
806             </ul>
807           </div>
808
809           <div style="color: rgb(204, 0, 0); display: none;" id="locterr">
810             <font face="arial,sans-serif" size="-1">Please enter a valid US
811             city or zip code<br>
812             <br></font>
813           </div>
814
815           <div style="color: rgb(204, 0, 0); display: none;" id="locserr">
816             <font face="arial,sans-serif" size="-1">Server error. Please try
817             again.<br>
818             <br></font>
819           </div><font face="arial,sans-serif" size="-1">Use as the default
820           location in Google Maps, customized search results, and other Google
821           products:<br>
822           <input name="uulo" value="1" type="hidden"><input name="muul"
823           value="4_20" type="hidden"><input name="luul" size="60" value=""
824           type="text"><br>
825           This location is saved on this computer.
826           <a href="/support/websearch/bin/answer.py?answer=35892&amp;hl=en">
827           Learn more</a><br>
828           <br></font>
829         </td>
830       </tr>
831     </tbody>
832   </table>
833
834   <table width="100%" border="0" cellpadding="0" cellspacing="0">
835     <tbody>
836       <tr>
837         <td colspan="4" bgcolor="#CBDCED"><img alt="" width="1" height="1"></td>
838       </tr>
839
840       <tr>
841         <td rowspan="2" width="1" bgcolor="#CBDCED">
842         <img alt="" width="2" height="1"></td>
843
844         <td width="175" nowrap="nowrap">
845           &nbsp;<br>
846           &nbsp;
847           <h2>SafeSearch Filtering</h2>
848         </td>
849         <td><br>
850         <font face="arial,sans-serif" size="-1">
851         <a href="http://www.google.com/">
852         Google's SafeSearch</a> blocks web pages containing explicit sexual
853         content from appearing in search results.</font></td>
854       </tr>
855       <tr valign="top">
856         <td width="175" nowrap="nowrap">&nbsp;</td>
857         <td>
858           <div style="margin-bottom: 1.2em; font: smaller arial,sans-serif;">
859             <input id="stf" name="safeui" value="on" type="radio">
860             <label for="stf">Use strict filtering&nbsp;(Filter both explicit
861             text and explicit images)</label><br>
862             <input id="modf" name="safeui" value="images" checked="checked"
863             type="radio"><label for="modf">Use moderate
864             filtering&nbsp;(Filter explicit images only - default
865             behavior)</label><br>
866             <input id="nof" name="safeui" value="off" type="radio">
867             <label for="nof">Do not filter my search results</label>
868           </div>
869           <p style="margin-bottom: 1.2em; font-size: smaller;">This will apply
870           strict filtering to all searches from this computer using Firefox.
871           <a href="http://www.google.com/">Learn more</a></p>
872         </td>
873       </tr>
874     </tbody>
875   </table>
876   <table width="100%" border="0" cellpadding="0" cellspacing="0">
877     <tbody>
878       <tr>
879         <td colspan="4" bgcolor="#CBDCED"><img alt="" width="1" height="1"></td>
880       </tr>
881
882       <tr>
883         <td width="1" bgcolor="#CBDCED"><img alt="" width="2" height="1"></td>
884
885         <td valign="top" width="175" nowrap="nowrap">
886           &nbsp;<br>
887           &nbsp;
888
889           <h2>Number of Results</h2>
890         </td>
891
892         <td>&nbsp;<br>
893         <font face="arial,sans-serif" size="-1">Google's default (10 results)
894         provides the fastest results.<br>
895         Display <select name="num">
896           <option value="10" selected="selected">
897             10
898           </option>
899
900           <option value="20">
901             20
902           </option>
903
904           <option value="30">
905             30
906           </option>
907
908           <option value="50">
909             50
910           </option>
911
912           <option value="100">
913             100
914           </option>
915         </select> results per page.<br>
916         &nbsp;</font></td>
917       </tr>
918     </tbody>
919   </table>
920
921   <table width="100%" border="0" cellpadding="0" cellspacing="0">
922     <tbody>
923       <tr>
924         <td colspan="4" bgcolor="#CBDCED"><img alt="" width="1" height="1"></td>
925       </tr>
926
927       <tr>
928         <td width="1" bgcolor="#CBDCED"><img alt="" width="2" height="1"></td>
929
930         <td valign="top" width="175" nowrap="nowrap">
931           &nbsp;<br>
932           &nbsp;
933
934           <h2>Results Window</h2><a name="safeui" id="safeui">&nbsp;</a>
935         </td>
936
937         <td>&nbsp;<br>
938         <font face="arial,sans-serif" size="-1"><input id="nwc" name="newwindow"
939         value="1" type="checkbox">&nbsp; <label for="nwc">Open
940         search results in a new browser window.</label></font><br>
941         &nbsp;</td>
942       </tr>
943     </tbody>
944   </table>
945
946   <table width="100%" border="0" cellpadding="0" cellspacing="0">
947     <tbody>
948       <tr>
949         <td colspan="4" bgcolor="#CBDCED"><img alt="" width="1" height="1"></td>
950       </tr>
951
952       <tr>
953         <td width="1" bgcolor="#CBDCED"><img alt="" width="2" height="1"></td>
954
955         <td valign="top" width="175" nowrap="nowrap">
956           &nbsp;<br>
957           &nbsp;
958
959           <h2>Google Instant</h2>
960         </td>
961
962         <td>&nbsp;<br>
963         <font face="arial,sans-serif" size="-1"><input id="suggon" name="suggon"
964         value="1" checked="checked" type="radio"><label for="suggon">Use Google
965         Instant predictions and results appear while typing</label><br>
966         <input id="suggmid" name="suggon" value="2" type="radio">
967         <label for="suggmid">Do not use Google Instant</label><br>
968         <br>
969         Signed-in users can remove personalized predictions from their
970         <a href="/history">Web History</a>. <a href="http://www.google.com/">
971         Learn more</a><br>
972         <br>
973         &nbsp;</font></td>
974       </tr>
975
976       <tr>
977         <td colspan="4" bgcolor="#CBDCED"><img alt="" width="1" height="2"></td>
978       </tr>
979     </tbody>
980   </table><br>
981   */});
982   var submitButton = document.getElementsByName('submit2')[0];
983   assertEquals(true, cvox.DomUtil.isControl(submitButton));
984   var selectControl = document.getElementsByName('hl')[0];
985   assertEquals(true, cvox.DomUtil.isControl(selectControl));
986   var checkbox = $('paf');
987   assertEquals(true, cvox.DomUtil.isControl(checkbox));
988   var textInput = document.getElementsByName('luul')[0];
989   assertEquals(true, cvox.DomUtil.isControl(textInput));
990   var radioButton = $('suggmid');
991   assertEquals(true, cvox.DomUtil.isControl(radioButton));
992   var h1Elem = document.getElementsByTagName('h1');
993   assertEquals(false, cvox.DomUtil.isControl(h1Elem));
994 });
995
996 /** Test if something is an ARIA control. @export */
997 TEST_F('CvoxDomUtilUnitTest', 'IsAriaControl', function() {
998   this.loadDoc(function() {/*!
999   <li id="cb1" role="checkbox" tabindex="0" aria-checked="false"
1000   aria-describedby="cond desc1">
1001       Lettuce
1002   </li>
1003   <li id="larger1" role="button" tabindex="0" aria-pressed="false"
1004   aria-labelledby="larger_label">+</li>
1005   <li id="r1" role="radio" tabindex="-1" aria-checked="false">Thai</li>
1006   <li id="treeitem1" role="treeitem" tabindex="-1">Oranges</li>
1007   */});
1008   var checkbox = $('cb1');
1009   assertEquals(true, cvox.DomUtil.isControl(checkbox));
1010   var button = $('larger1');
1011   assertEquals(true, cvox.DomUtil.isControl(button));
1012   var radio = $('r1');
1013   assertEquals(true, cvox.DomUtil.isControl(radio));
1014   var treeitem = $('treeitem1');
1015   assertEquals(false, cvox.DomUtil.isControl(treeitem));
1016 });
1017
1018 /** Test if something is an focusable. @export */
1019 TEST_F('CvoxDomUtilUnitTest', 'IsFocusable', function() {
1020   this.loadDoc(function() {/*!
1021   <a id="focus_link" href="#">Link</a>
1022   <a id="focus_anchor">Unfocusable anchor</a>
1023   <input id="focus_input" value="Input" />
1024   <select id="focus_select"><option>Select</option></select>
1025   <button id="focus_button1">Button</button>
1026   <button id="focus_button2" tabindex="-1">Button 2</button>
1027   <button id="focus_button3" tabindex="0">Button 3</button>
1028   <button id="focus_button4" tabindex="1">Button 4</button>
1029   <div id="focus_div1">Div</div>
1030   <div id="focus_div2" tabindex="-1">Div 2</div>
1031   <div id="focus_div3" tabindex="0">Div 3</div>
1032   <div id="focus_div4" tabindex="1">Div 4</div>
1033   */});
1034   var node;
1035   node = $('focus_link');
1036   assertEquals(true, cvox.DomUtil.isFocusable(node));
1037   node = $('focus_anchor');
1038   assertEquals(false, cvox.DomUtil.isFocusable(node));
1039   node = $('focus_input');
1040   assertEquals(true, cvox.DomUtil.isFocusable(node));
1041   node = $('focus_select');
1042   assertEquals(true, cvox.DomUtil.isFocusable(node));
1043   node = $('focus_button1');
1044   assertEquals(true, cvox.DomUtil.isFocusable(node));
1045   node = $('focus_button2');
1046   assertEquals(true, cvox.DomUtil.isFocusable(node));
1047   node = $('focus_button3');
1048   assertEquals(true, cvox.DomUtil.isFocusable(node));
1049   node = $('focus_button4');
1050   assertEquals(true, cvox.DomUtil.isFocusable(node));
1051   node = $('focus_div1');
1052   assertEquals(false, cvox.DomUtil.isFocusable(node));
1053   node = $('focus_div2');
1054   assertEquals(true, cvox.DomUtil.isFocusable(node));
1055   node = $('focus_div3');
1056   assertEquals(true, cvox.DomUtil.isFocusable(node));
1057   node = $('focus_div4');
1058   assertEquals(true, cvox.DomUtil.isFocusable(node));
1059
1060   // Test it with null.
1061   assertEquals(false, cvox.DomUtil.isFocusable(null));
1062
1063   // Test it with something that's not an element.
1064   assertEquals(false, cvox.DomUtil.isFocusable(new Object()));
1065
1066   // Test it with a Text node.
1067   node = $('focus_button1').firstChild;
1068   assertEquals(false, cvox.DomUtil.isFocusable(node));
1069 });
1070
1071 /** Some additional tests for getName function. */
1072 TEST_F('CvoxDomUtilUnitTest', 'GetName', function() {
1073   this.loadDoc(function() {/*!
1074   <span id="test-span" aria-labelledby="fake-id">Some text</span>
1075   <label id="label1">One</label>
1076   <label id="label3">Label</label>
1077   <div id="test-div" aria-labelledby="label1 label2 label3"></div>
1078   */});
1079   var node = $('test-span');
1080   // Makes sure we can deal with invalid ids in aria-labelledby.
1081   var text = cvox.DomUtil.collapseWhitespace(cvox.DomUtil.getName(node));
1082   assertEquals('Some text', text);
1083   node = $('test-div');
1084   text = cvox.DomUtil.collapseWhitespace(cvox.DomUtil.getName(node));
1085   assertEquals('One Label', cvox.DomUtil.getName(node));
1086 });
1087
1088 /** Test for getLinkURL. */
1089 TEST_F('CvoxDomUtilUnitTest', 'GetLinkURL', function() {
1090   this.loadDoc(function() {/*!
1091   <a id="l1" name="nohref">Anchor</a>
1092   <a id="l2" href="">Empty link</a>
1093   <a id="l3" href="#">Link to self</a>
1094   <a id="l4" href="http://google.com">Google</a>
1095   <span id="l5" role="link" onClick="javascript:alert('?')">Something</span>
1096   <div id="l6" role="link">Div with link role</a>
1097   */});
1098   var node = $('l1');
1099   assertEquals('', cvox.DomUtil.getLinkURL(node));
1100   node = $('l2');
1101   assertEquals('', cvox.DomUtil.getLinkURL(node));
1102   node = $('l3');
1103   assertEquals('Internal link', cvox.DomUtil.getLinkURL(node));
1104   node = $('l4');
1105   assertEquals('http://google.com', cvox.DomUtil.getLinkURL(node));
1106   node = $('l5');
1107   assertEquals('Unknown link', cvox.DomUtil.getLinkURL(node));
1108   node = $('l6');
1109   assertEquals('Unknown link', cvox.DomUtil.getLinkURL(node));
1110 });
1111
1112 /** Test for isDisabled. */
1113 TEST_F('CvoxDomUtilUnitTest', 'IsDisabled', function() {
1114   this.loadDoc(function() {/*!
1115   <input id="button1" type="button" value="Press me!"/>
1116   <input id="button2" type="button" value="Don't touch me!" disabled/>
1117   */});
1118   var node = $('button1');
1119   assertEquals(false, cvox.DomUtil.isDisabled(node));
1120   node = $('button2');
1121   assertEquals(true, cvox.DomUtil.isDisabled(node));
1122 });
1123
1124 /** Test for a tree with aria-expanded attribute. */
1125 TEST_F('CvoxDomUtilUnitTest', 'Tree', function() {
1126   this.loadDoc(function() {/*!
1127   <div id=":0" role="tree" aria-selected="false" aria-expanded="true"
1128     aria-level="0" aria-labelledby=":0.label" tabindex="0"
1129     aria-activedescendant=":1">
1130     <span id=":0.label">Countries</span>
1131       <div class="goog-tree-item" id=":1" role="treeitem" aria-selected="true"
1132           aria-expanded="false" aria-labelledby=":1.label" aria-level="1">
1133         <span id=":1.label">A</span>
1134       </div>
1135       <div class="goog-tree-item" id=":2" role="treeitem" aria-selected="false"
1136           aria-expanded="false" aria-labelledby=":2.label" aria-level="1">
1137         <span id=":2.label">B<span>
1138       </div>
1139       <div class="goog-tree-item" id=":3" role="treeitem" aria-selected="false"
1140           aria-expanded="true" aria-labelledby=":3.label" aria-level="1">
1141         <span id=":3.label">C</span>
1142         <div class="goog-tree-children" role="group">
1143           <div class="goog-tree-item" id=":3a" role="treeitem"
1144               aria-selected="false" aria-expanded="false"
1145               aria-labelledby=":3a.label" aria-level="2">
1146             <span id=":3a.label">Chile</span>
1147           </div>
1148           <div class="goog-tree-item" id=":3b" role="treeitem"
1149               aria-selected="false" aria-expanded="false"
1150               aria-labelledby=":3b.label" aria-level="2">
1151             <span id=":3b.label">China</span>
1152           </div>
1153           <div class="goog-tree-item" id=":3c" role="treeitem"
1154               aria-selected="false" aria-expanded="false"
1155               aria-labelledby=":3c.label" aria-level="2">
1156             <span id=":3c.label">Christmas Island</span>
1157           </div>
1158           <div class="goog-tree-item" id=":3d" role="treeitem"
1159               aria-selected="false" aria-expanded="false"
1160               aria-labelledby=":3d.label" aria-level="2">
1161             <span id=":3d.label">Cocos (Keeling) Islands</span>
1162           </div>
1163         </div>
1164       </div>
1165   </div>
1166   */});
1167   var node = $(':0');
1168   assertEquals('A Collapsed Selected 1 of 3',
1169       cvox.DomUtil.getControlValueAndStateString(node));
1170   node = $(':1');
1171   assertEquals('A Collapsed Selected 1 of 3',
1172       cvox.DomUtil.getControlValueAndStateString(node));
1173   node = $(':2');
1174   assertEquals('B Collapsed Not selected 2 of 3',
1175       cvox.DomUtil.getControlValueAndStateString(node));
1176   node = $(':3');
1177   assertEquals('C Expanded Not selected 3 of 3',
1178       cvox.DomUtil.getControlValueAndStateString(node));
1179     node = $(':3b');
1180   assertEquals('China Collapsed Not selected 2 of 4',
1181       cvox.DomUtil.getControlValueAndStateString(node));
1182 });
1183
1184 /** Test for tables with different border specifications */
1185 TEST_F('CvoxDomUtilUnitTest', 'TableBorders', function() {
1186   this.loadDoc(function() {/*!
1187   <table id=":0" border="1">
1188     <tr>
1189       <td>A</td>
1190     </tr>
1191   </table>
1192   <table id=":1" border="0">
1193     <tr>
1194       <td>A</td>
1195     </tr>
1196   </table>
1197   <table id=":2" border="0px">
1198     <tr>
1199       <td>A</td>
1200     </tr>
1201   </table>
1202   <table id=":3" frame="box">
1203     <tr>
1204       <td>A</td>
1205     </tr>
1206   </table>
1207   <table id=":4" frame="void">
1208     <tr>
1209       <td>A</td>
1210     </tr>
1211   </table>
1212   <table id=":5" style="border-width: medium">
1213     <tr>
1214       <td>A</td>
1215     </tr>
1216   </table>
1217   <table id=":6" style="border-width: medium; border-style: none">
1218     <tr>
1219       <td>A</td>
1220     </tr>
1221   </table>
1222   <table id=":7" style="border-color: red">
1223     <tr>
1224       <td>A</td>
1225     </tr>
1226   </table>
1227   <table id=":8" style="border-style: dotted; border-width: 0px">
1228     <tr>
1229       <td>A</td>
1230     </tr>
1231   </table>
1232   <table id=":9" style="border-width: 0px">
1233     <tr>
1234       <td>A</td>
1235     </tr>
1236   </table>
1237   <table id=":10" style="border: 0px">
1238     <tr>
1239       <td>A</td>
1240     </tr>
1241   </table>
1242   <table id=":11" style="border: 0">
1243     <tr>
1244       <td>A</td>
1245     </tr>
1246   </table>
1247   */});
1248   var node = $(':0');
1249   assertTrue(cvox.DomUtil.hasBorder(node));
1250
1251   node = $(':1');
1252   assertFalse(cvox.DomUtil.hasBorder(node));
1253
1254   node = $(':2');
1255   assertFalse(cvox.DomUtil.hasBorder(node));
1256
1257   node = $(':3');
1258   assertTrue(cvox.DomUtil.hasBorder(node));
1259
1260   node = $(':4');
1261   assertFalse(cvox.DomUtil.hasBorder(node));
1262
1263   node = $(':5');
1264   assertTrue(cvox.DomUtil.hasBorder(node));
1265
1266   node = $(':6');
1267   assertFalse(cvox.DomUtil.hasBorder(node));
1268
1269   node = $(':7');
1270   assertTrue(cvox.DomUtil.hasBorder(node));
1271
1272   node = $(':8');
1273   assertFalse(cvox.DomUtil.hasBorder(node));
1274
1275   node = $(':9');
1276   assertFalse(cvox.DomUtil.hasBorder(node));
1277
1278   node = $(':10');
1279   assertFalse(cvox.DomUtil.hasBorder(node));
1280
1281   node = $(':11');
1282   assertFalse(cvox.DomUtil.hasBorder(node));
1283 });
1284
1285 /** Tests for shallowChildlessClone */
1286 TEST_F('CvoxDomUtilUnitTest', 'ShallowChildlessClone', function() {
1287   this.loadDoc(function() {/*!
1288     <div id='simple'>asdf</div>
1289     <div id='expectedSimpleClone'>asdf</div>
1290     <div id='oneLevel'><div>asdf</div></div>
1291     <div id='expectedOneLevelClone'><div></div></div>
1292     <div id='withAttrs'><div class="asdf">asdf</div></div>
1293     <div id='expectedWithAttrsClone'><div class="asdf"></div></div>
1294   */});
1295
1296   var simple = $('simple').firstChild;
1297   var expectedSimpleClone = $('expectedSimpleClone').firstChild;
1298   var oneLevel = $('oneLevel').firstChild;
1299   var expectedOneLevelClone = $('expectedOneLevelClone').firstChild;
1300   var withAttrs = $('withAttrs').firstChild;
1301   var expectedWithAttrsClone = $('expectedWithAttrsClone').firstChild;
1302
1303   var simpleClone = cvox.DomUtil.shallowChildlessClone(simple);
1304   this.assertEqualsAsText_(simpleClone, expectedSimpleClone);
1305
1306   var oneLevelClone = cvox.DomUtil.shallowChildlessClone(oneLevel);
1307   this.assertEqualsAsText_(oneLevelClone, expectedOneLevelClone);
1308
1309   var withAttrsClone = cvox.DomUtil.shallowChildlessClone(withAttrs);
1310   this.assertEqualsAsText_(withAttrsClone, expectedWithAttrsClone);
1311 });
1312
1313 /** Tests for deepClone */
1314 TEST_F('CvoxDomUtilUnitTest', 'DeepClone', function() {
1315   this.loadDoc(function() {/*!
1316     <div id='simple'>asdf</div>
1317   */});
1318   var simpleClone = cvox.DomUtil.deepClone($('simple'));
1319   this.assertEqualsAsText_(simpleClone, $('simple'));
1320
1321   this.loadDoc(function() {/*!
1322     <div id="withAttrs" class="asdf">asdf</div>
1323   */});
1324   var withAttrsClone = cvox.DomUtil.deepClone($('withAttrs'));
1325   this.assertEqualsAsText_(withAttrsClone, $('withAttrs'));
1326 });
1327
1328 /** Tests for findNode */
1329 TEST_F('CvoxDomUtilUnitTest', 'FindNode', function() {
1330   this.loadDoc(function() {/*!
1331     <div id="root">
1332       <p id="a">a</p>
1333       <a href="#" id="b">b</a>
1334     </div>
1335   */});
1336   var f = cvox.DomUtil.findNode;
1337   var node = f($('root'), function(n) {return n.id == 'b';});
1338   assertEquals('b', node.id);
1339 });
1340
1341 /** Tests for getState for a list */
1342 TEST_F('CvoxDomUtilUnitTest', 'ListLength', function() {
1343   this.loadDoc(function() {/*!
1344     <ul id="ul1">
1345       <li>A
1346       <li>B
1347       <li>C
1348     </ul>
1349     <ul id="ul2">
1350       <li aria-setsize="10">A
1351       <li aria-setsize="10">B
1352       <li aria-setsize="10">C
1353     </ul>
1354   */});
1355   var ul1 = $('ul1');
1356   assertEquals('with 3 items',
1357       cvox.DomUtil.collapseWhitespace(cvox.DomUtil.getState(ul1)));
1358
1359   var ul2 = $('ul2');
1360   assertEquals('with 10 items',
1361       cvox.DomUtil.collapseWhitespace(cvox.DomUtil.getState(ul2)));
1362 });
1363
1364 /** Tests for hasLongDesc */
1365 TEST_F('CvoxDomUtilUnitTest', 'HasLongDesc', function() {
1366   this.loadDoc(function() {/*!
1367     <img id="img0" longdesc="desc.html" src="img0.jpg"></img>
1368     <img id="img1" src="img1.jpg"></img>
1369   */});
1370   var img0 = $('img0');
1371   assertEquals(true, cvox.DomUtil.hasLongDesc(img0));
1372
1373   var img1 = $('img1');
1374   assertEquals(false, cvox.DomUtil.hasLongDesc(img1));
1375 });
1376
1377 /** Tests for various link leaf types. */
1378 TEST_F('CvoxDomUtilUnitTest', 'LinkLeaf', function() {
1379   this.loadDoc(function() {/*!
1380     <a id='leaf' href='google.com'><strong>Click</strong><div>here</div></a>
1381     <a id='non-leaf' href='google.com'>Click <h2>here</h2></a>
1382   */});
1383   var leaf = $('leaf');
1384   var nonLeaf = $('non-leaf');
1385   assertTrue(cvox.DomUtil.isLeafNode(leaf));
1386   assertFalse(cvox.DomUtil.isLeafNode(nonLeaf));
1387 });
1388
1389
1390 /** Test the value and state of a multiple select. */
1391 TEST_F('CvoxDomUtilUnitTest', 'MultipleSelectValue', function() {
1392   this.loadDoc(function() {/*!
1393     <select id='cars' multiple>
1394       <option value="volvo">Volvo</option>
1395       <option value="saab">Saab</option>
1396       <option value="opel" selected>Opel</option>
1397       <option value="audi" selected>Audi</option>
1398     </select>
1399   */});
1400   var cars = $('cars');
1401   assertEquals('Opel to Audi', cvox.DomUtil.getValue(cars));
1402   assertEquals('selected 2 items', cvox.DomUtil.getState(cars));
1403 });
1404
1405
1406 /**
1407  * Test correctness of elementToPoint.
1408  *
1409  * Absolute positioning of the container is used to avoid the window of the
1410  * browser being too small to contain the test elements.
1411  */
1412 TEST_F('CvoxDomUtilUnitTest', 'ElementToPoint', function() {
1413   this.loadDoc(function() {/*!
1414     <div style="position: absolute; top: 0; left: 0">
1415       <a id='one' href='#a'>First</a>
1416       <p id='two'>Some text</p>
1417       <ul><li id='three'>LI</li><li>LI2</li></ul>
1418     </div>
1419   */});
1420   var one = $('one');
1421   var two = $('two');
1422   var three = $('three');
1423
1424   var oneHitPoint = cvox.DomUtil.elementToPoint(one);
1425   var twoHitPoint = cvox.DomUtil.elementToPoint(two);
1426   var threeHitPoint = cvox.DomUtil.elementToPoint(three);
1427
1428   assertEquals(one, document.elementFromPoint(oneHitPoint.x, oneHitPoint.y));
1429   assertEquals(two, document.elementFromPoint(twoHitPoint.x, twoHitPoint.y));
1430   assertEquals(three,
1431                document.elementFromPoint(threeHitPoint.x, threeHitPoint.y));
1432 });
1433
1434 /** Tests we compute the correct name for hidden aria labelledby nodes. */
1435 TEST_F('CvoxDomUtilUnitTest', 'HiddenAriaLabelledby', function() {
1436   this.loadDoc(function() {/*!
1437     <span id="acc_name" style="display: none">
1438       hello world!
1439     </span>
1440     <button id="button" aria-labelledby="acc_name">
1441   */});
1442   assertEquals('hello world!',
1443                cvox.DomUtil.getName($('button')));
1444 });
1445
1446 /** Tests that we compute the correct state for accesskeys. */
1447 TEST_F('CvoxDomUtilUnitTest', 'AccessKey', function() {
1448   this.loadDoc(function() {/*!
1449     <a id='accessKey' href="#f" title="Next page" accesskey="n">Next page</a>
1450   */});
1451   var a = $('accessKey');
1452   assertEquals('has access key, n', cvox.DomUtil.getState(a));
1453 });
1454
1455
1456 /** Tests that we compute the correct name for ordered listitems. */
1457 TEST_F('CvoxDomUtilUnitTest', 'OrderedListitem', function() {
1458   this.loadDoc(function() {/*!
1459     <ol id="fruits_ol">
1460       <li id='ol_li1'>apple
1461       <li id='ol_li2'>orange
1462       <li id='ol_li3'>strawberry
1463       <li id='ol_li4'>banana
1464     </ol>
1465   */});
1466   var li1 = $('ol_li1');
1467   var li2 = $('ol_li2');
1468   var li3 = $('ol_li3');
1469   var li4 = $('ol_li4');
1470   // Note that whitespace processing happens at a higher layer
1471   // (DescriptionUtil).
1472   assertEquals('1. apple',
1473                cvox.DomUtil.collapseWhitespace(cvox.DomUtil.getName(li1)));
1474   assertEquals('2. orange',
1475                cvox.DomUtil.collapseWhitespace(cvox.DomUtil.getName(li2)));
1476   assertEquals('3. strawberry',
1477                cvox.DomUtil.collapseWhitespace(cvox.DomUtil.getName(li3)));
1478   assertEquals('4. banana',
1479                cvox.DomUtil.collapseWhitespace(cvox.DomUtil.getName(li4)));
1480
1481   $('fruits_ol').style.listStyleType = 'lower-latin';
1482
1483   assertEquals('A. apple',
1484                cvox.DomUtil.collapseWhitespace(cvox.DomUtil.getName(li1)));
1485   assertEquals('B. orange',
1486                cvox.DomUtil.collapseWhitespace(cvox.DomUtil.getName(li2)));
1487   assertEquals('C. strawberry',
1488                cvox.DomUtil.collapseWhitespace(cvox.DomUtil.getName(li3)));
1489   assertEquals('D. banana',
1490                cvox.DomUtil.collapseWhitespace(cvox.DomUtil.getName(li4)));
1491 });
1492
1493 /** Tests a node with title, and textContent containing only whitespace. */
1494 TEST_F('CvoxDomUtilUnitTest', 'TitleOverridesInnerWhitespace', function() {
1495   this.loadDoc(function() {/*!
1496     <button id="btn1" title="Remove from Chrome">
1497       <span class="lid"></span>
1498       <span class="can"></span>
1499     </button>
1500   */});
1501   var btn1 = $('btn1');
1502   assertEquals('Remove from Chrome', cvox.DomUtil.getName(btn1));
1503 });
1504
1505 /** Test memoization. **/
1506 TEST_F('CvoxDomUtilUnitTest', 'Memoization', function() {
1507   this.loadDoc(function() {/*!
1508     <div id="container">
1509     </div>
1510   */});
1511
1512   // Nest divs 100 levels deep.
1513   var container = $('container');
1514   var outer = container;
1515   for (var i = 0; i < 100; i++) {
1516     var inner = document.createElement('div');
1517     outer.appendChild(inner);
1518     outer = inner;
1519   }
1520   var target = document.createElement('p');
1521   target.innerHTML = 'Text';
1522   outer.appendChild(target);
1523
1524   var iterations = 200;
1525
1526   function logTime(msg, fn) {
1527     var t0 = new Date();
1528     fn();
1529     console.log(msg + ' elapsed time: ' + (new Date() - t0) + ' ms');
1530   }
1531
1532   // First, test without memoization.
1533   logTime('No memoization', function() {
1534     container.style.visibility = 'hidden';
1535     for (var i = 0; i < iterations; i++) {
1536       assertFalse(cvox.DomUtil.isVisible(target));
1537     }
1538     container.style.visibility = 'visible';
1539     for (var i = 0; i < iterations; i++) {
1540       assertTrue(cvox.DomUtil.isVisible(target));
1541     }
1542   });
1543
1544   // Now test with memoization enabled.
1545   logTime('With memoization', function() {
1546     cvox.Memoize.scope(function() {
1547       container.style.visibility = 'hidden';
1548       for (var i = 0; i < iterations; i++) {
1549         assertFalse(cvox.DomUtil.isVisible(target));
1550       }
1551     });
1552     cvox.Memoize.scope(function() {
1553       container.style.visibility = 'visible';
1554       for (var i = 0; i < iterations; i++) {
1555         assertTrue(cvox.DomUtil.isVisible(target));
1556       }
1557     });
1558   });
1559
1560   // Finally as a sanity check that things are being memoized, turn on
1561   // memoization and show that we get the wrong result if we change the
1562   // DOM and call isVisible again.
1563   cvox.Memoize.scope(function() {
1564     container.style.visibility = 'hidden';
1565     assertFalse(cvox.DomUtil.isVisible(target));
1566
1567     container.style.visibility = 'visible';
1568     // This should be true! It will return the wrong answer because
1569     // we're deliberately leaving memoization on while modifying the DOM.
1570     assertFalse(cvox.DomUtil.isVisible(target));
1571   });
1572 });