• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
6GEN_INCLUDE(['../testing/chromevox_unittest_base.js']);
7
8/**
9 * Test fixture.
10 * @constructor
11 * @extends {ChromeVoxUnitTestBase}
12 */
13function CvoxDomUtilUnitTest() {}
14
15CvoxDomUtilUnitTest.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
104TEST_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 */
153TEST_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 */
183TEST_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 */
223TEST_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 */
274TEST_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 */
293TEST_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 */
360TEST_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
416TEST_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 */
434TEST_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 */
444TEST_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 */
457TEST_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 */
478TEST_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 */
501TEST_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. */
523TEST_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 */
538TEST_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 */
602TEST_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 */
1003TEST_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 */
1025TEST_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. */
1078TEST_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. */
1095TEST_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. */
1119TEST_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. */
1131TEST_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 */
1191TEST_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 */
1292TEST_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 */
1320TEST_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 */
1335TEST_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 */
1348TEST_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 */
1371TEST_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. */
1384TEST_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. */
1397TEST_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 */
1418TEST_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. */
1441TEST_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. */
1453TEST_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. */
1463TEST_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. */
1500TEST_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. **/
1512TEST_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});
1579