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