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.
5 chrome.test.runWithNativesEnabled(function() {
6 var moduleSystem = chrome.test.getModuleSystem(window);
7 window.AutomationRootNode =
8 moduleSystem.require('automationNode').AutomationRootNode;
9 window.privates = moduleSystem.privates;
11 window.automationUtil = function() {};
12 window.automationUtil.storeTreeCallback = function() {};
13 window.automationUtil.treeChangeObservers = [];
16 var assertEq = chrome.test.assertEq;
17 var assertFalse = chrome.test.assertFalse;
18 var assertTrue = chrome.test.assertTrue;
19 var assertIsDef = function(obj) {
20 assertTrue(obj !== null && obj !== undefined);
22 var assertIsNotDef = function(obj) {
23 assertTrue(obj === null || obj === undefined);
25 var succeed = chrome.test.succeed;
28 function testAutomationRootNode() {
29 var root = new AutomationRootNode();
30 assertTrue(root.isRootNode);
35 function testAriaRelationshipAttributes() {
37 'eventType': 'loadComplete',
38 'processID': 17, 'routingID': 2, 'targetID': 1,
39 'update': { 'nodeIdToClear': 0, 'nodes': [
41 'id': 1, 'role': 'rootWebArea',
42 'boolAttributes': {'docLoaded': true },
43 'childIds': [5, 6, 7, 8, 9, 10, 11]
46 'id': 11, 'role': 'div',
48 'htmlAttributes': {'id': 'target' }
51 'id': 5, 'role': 'div',
53 'htmlAttributes': {'aria-activedescendant': 'target',
54 'id': 'activedescendant'},
55 'intAttributes': {'activedescendantId': 11},
58 'id': 6, 'role': 'div',
60 'htmlAttributes': {'aria-controls': 'target', 'id': 'controlledBy'},
61 'intlistAttributes': {'controlsIds': [11]},
64 'id': 7, 'role': 'div',
66 'htmlAttributes': {'aria-describedby': 'target', 'id': 'describedBy'},
67 'intlistAttributes': {'describedbyIds': [11, 6]},
70 'id': 8, 'role': 'div',
72 'htmlAttributes': {'aria-flowto': 'target', 'id': 'flowTo'},
73 'intlistAttributes': {'flowtoIds': [11]},
76 'id': 9, 'role': 'div',
78 'htmlAttributes': {'aria-labelledby': 'target', 'id': 'labelledBy'},
79 'intlistAttributes': {'labelledbyIds': [11]}
82 'id': 10, 'role': 'div',
84 'htmlAttributes': {'aria-owns': 'target', 'id': 'owns'},
85 'intlistAttributes': {'ownsIds': [11]},
90 var tree = new AutomationRootNode();
92 privates(tree).impl.onAccessibilityEvent(data);
97 var activedescendant = tree.firstChild;
98 assertIsDef(activedescendant);
99 assertEq('activedescendant', activedescendant.attributes.id);
102 activedescendant.attributes['aria-activedescendant'].attributes.id);
104 assertFalse(activedescendant.activedescendant == null,
105 'activedescendant should not be null');
108 activedescendant.activedescendant.attributes.id);
109 assertIsNotDef(activedescendant.attributes.activedescendantId);
111 var controlledBy = activedescendant.nextSibling;
112 assertIsDef(controlledBy);
113 assertEq('controlledBy', controlledBy.attributes.id);
114 assertEq(1, controlledBy.attributes['aria-controls'].length);
116 controlledBy.attributes['aria-controls'][0].attributes.id);
117 assertEq(1, controlledBy.controls.length);
118 assertEq('target', controlledBy.controls[0].attributes.id);
119 assertIsNotDef(controlledBy.attributes.controlledbyIds);
121 var describedBy = controlledBy.nextSibling;
122 assertIsDef(describedBy);
123 assertEq('describedBy', describedBy.attributes.id);
124 assertEq(2, describedBy.attributes['aria-describedby'].length);
126 describedBy.attributes['aria-describedby'][0].attributes.id);
127 assertEq('controlledBy',
128 describedBy.attributes['aria-describedby'][1].attributes.id);
129 assertEq(2, describedBy.describedby.length);
130 assertEq('target', describedBy.describedby[0].attributes.id);
131 assertEq('controlledBy',
132 describedBy.describedby[1].attributes.id);
133 assertIsNotDef(describedBy.attributes.describedbyIds);
135 var flowTo = describedBy.nextSibling;
137 assertEq('flowTo', flowTo.attributes.id);
138 assertEq(1, flowTo.attributes['aria-flowto'].length);
140 flowTo.attributes['aria-flowto'][0].attributes.id);
141 assertEq(1, flowTo.flowto.length);
142 assertEq('target', flowTo.flowto[0].attributes.id);
143 assertIsNotDef(flowTo.attributes.flowtoIds);
145 var labelledBy = flowTo.nextSibling;
146 assertIsDef(labelledBy);
147 assertEq('labelledBy', labelledBy.attributes.id);
148 assertEq(1, labelledBy.attributes['aria-labelledby'].length);
150 labelledBy.attributes['aria-labelledby'][0].attributes.id);
151 assertEq(1, labelledBy.labelledby.length);
153 labelledBy.labelledby[0].attributes.id);
154 assertIsNotDef(labelledBy.attributes.labelledbyIds);
156 var owns = labelledBy.nextSibling;
158 assertEq('owns', owns.attributes.id);
159 assertEq(1, owns.attributes['aria-owns'].length);
160 assertEq('target', owns.attributes['aria-owns'][0].attributes.id);
161 assertEq(1, owns.owns.length);
162 assertEq('target', owns.owns[0].attributes.id);
163 assertIsNotDef(owns.attributes.ownsIds);
168 function testCannotSetAttribute() {
171 'nodeIdToClear': 0, 'nodes': [
173 'id': 1, 'role': 'rootWebArea',
174 'boolAttributes': {'docLoaded': true},
178 'id': 11, 'role': 'button',
179 'stringAttributes': {'name': 'foo'},
184 var tree = new AutomationRootNode();
185 assertTrue(privates(tree).impl.unserialize(update));
186 var button = tree.firstChild;
187 assertEq('button', button.role);
188 assertEq('foo', button.name);
190 assertEq('foo', button.name);
195 function testBadUpdateInvalidChildIds() {
198 'nodeIdToClear': 0, 'nodes': [
200 'id': 1, 'role': 'rootWebArea',
201 'boolAttributes': {'docLoaded': true},
202 'childIds': [5, 6, 7, 8, 9, 10, 11]
206 var tree = new AutomationRootNode();
208 // This is a bad update because the root references non existent child ids.
209 assertFalse(privates(tree).impl.unserialize(update));
214 function testMultipleUpdateNameChanged() {
217 'nodeIdToClear': 0, 'nodes': [
219 'id': 1, 'role': 'rootWebArea',
220 'boolAttributes': {'docLoaded': true},
224 'id': 11, 'role': 'button',
225 'stringAttributes': {'name': 'foo'},
230 // First, setup the initial tree.
231 var tree = new AutomationRootNode();
232 assertTrue(privates(tree).impl.unserialize(update));
233 var button = tree.firstChild;
234 assertEq('button', button.role);
235 assertEq('foo', button.name);
237 // Now, apply an update that changes the button's name.
238 // Remove the root since the native serializer stops at the LCA.
239 update.nodes.splice(0, 1);
240 update.nodes[0].stringAttributes.name = 'bar';
242 // Make sure the name changes.
243 assertTrue(privates(tree).impl.unserialize(update));
244 assertEq('bar', button.name);
249 function testDocumentAndScrollableMixins() {
250 var update = { 'nodeIdToClear': 0, 'nodes': [
252 'id': 1, 'role': 'rootWebArea',
253 'boolAttributes': { 'docLoaded': false },
254 'stringAttributes': { 'docUrl': 'chrome://terms',
255 'docTitle': 'Google Chrome Terms of Service' },
256 'intAttributes': { 'scrollY': 583,
257 'scrollYMax': 9336 },
258 'floatAttributes': { 'docLoadingProgress': 0.9 },
262 'id': 2, 'role': 'div',
264 'htmlAttributes': { 'id': 'child' },
268 var tree = new AutomationRootNode();
269 assertTrue(privates(tree).impl.unserialize(update));
270 assertEq(false, tree.docLoaded);
271 assertEq('chrome://terms', tree.docUrl);
272 assertEq('Google Chrome Terms of Service', tree.docTitle);
273 assertEq('0.9', tree.docLoadingProgress.toPrecision(1));
274 assertEq(583, tree.scrollY);
275 assertEq(9336, tree.scrollYMax);
276 // Default values will be set for mixin attributes even if not in data.
277 assertEq(0, tree.scrollYMin);
278 assertEq(0, tree.scrollX);
279 assertEq(0, tree.scrollXMin);
280 assertEq(0, tree.scrollXMax);
285 function testEditableTextMixins() {
286 var update = { 'nodeIdToClear': 0, 'nodes': [
288 'id': 1, 'role': 'rootWebArea',
289 'boolAttributes': { 'docLoaded': true },
290 'stringAttributes': { 'docUrl': 'chrome://terms',
291 'docTitle': 'Google Chrome Terms of Service' },
292 'intAttributes': { 'scrollY': 583,
293 'scrollYMax': 9336 },
297 'id': 2, 'role': 'textField',
298 'intAttributes': { 'textSelStart': 10, 'textSelEnd': 20 },
302 'id': 3, 'role': 'textField',
308 var tree = new AutomationRootNode();
309 assertTrue(privates(tree).impl.unserialize(update));
310 assertEq(true, tree.docLoaded);
311 assertFalse('textSelStart' in tree);
312 assertFalse('textSelEnd' in tree);
313 var textField = tree.firstChild;
314 assertEq(10, textField.textSelStart);
315 assertEq(20, textField.textSelEnd);
316 var textArea = textField.nextSibling;
317 assertEq(-1, textArea.textSelStart);
318 assertEq(-1, textArea.textSelEnd);
323 function testRangeMixins() {
324 var update = { 'nodeIdToClear': 0, 'nodes': [
326 'id': 1, 'role': 'rootWebArea',
327 'boolAttributes': { 'docLoaded': true },
328 'stringAttributes': { 'docUrl': 'chrome://terms',
329 'docTitle': 'Google Chrome Terms of Service' },
330 'intAttributes': { 'scrollY': 583,
331 'scrollYMax': 9336 },
332 'childIds': [2, 3, 4, 5]
335 'id': 2, 'role': 'progressIndicator',
336 'floatAttributes': { 'valueForRange': 1.0,
337 'minValueForRange': 0.0,
338 'maxValueForRange': 1.0 },
342 'id': 3, 'role': 'scrollBar',
343 'floatAttributes': { 'valueForRange': 0.3,
344 'minValueForRange': 0.0,
345 'maxValueForRange': 1.0 },
349 'id': 4, 'role': 'slider',
350 'floatAttributes': { 'valueForRange': 3.0,
351 'minValueForRange': 1.0,
352 'maxValueForRange': 5.0 },
356 'id': 5, 'role': 'spinButton',
357 'floatAttributes': { 'valueForRange': 14.0,
358 'minValueForRange': 1.0,
359 'maxValueForRange': 31.0 },
364 var tree = new AutomationRootNode();
365 assertTrue(privates(tree).impl.unserialize(update));
366 assertEq(true, tree.docLoaded);
367 assertFalse('valueForRange' in tree);
368 assertFalse('minValueForRange' in tree);
369 assertFalse('maxValueForRange' in tree);
371 var progressIndicator = tree.firstChild;
372 assertEq(1.0, progressIndicator.valueForRange);
373 assertEq(0.0, progressIndicator.minValueForRange);
374 assertEq(1.0, progressIndicator.maxValueForRange);
376 var scrollBar = progressIndicator.nextSibling;
377 assertEq(0.3, scrollBar.valueForRange);
378 assertEq(0.0, scrollBar.minValueForRange);
379 assertEq(1.0, scrollBar.maxValueForRange);
381 var slider = scrollBar.nextSibling;
382 assertEq(3.0, slider.valueForRange);
383 assertEq(1.0, slider.minValueForRange);
384 assertEq(5.0, slider.maxValueForRange);
386 var spinButton = slider.nextSibling;
387 assertEq(14.0, spinButton.valueForRange);
388 assertEq(1.0, spinButton.minValueForRange);
389 assertEq(31.0, spinButton.maxValueForRange);
394 function testTableMixins() {
395 var update = { 'nodeIdToClear': 0, 'nodes': [
397 'id': 1, 'role': 'rootWebArea',
398 'boolAttributes': { 'docLoaded': true },
399 'stringAttributes': { 'docUrl': 'chrome://terms',
400 'docTitle': 'Google Chrome Terms of Service' },
401 'intAttributes': { 'scrollY': 583,
402 'scrollYMax': 9336 },
406 'id': 2, 'role': 'table',
408 'intAttributes': { tableRowCount: 2, tableColumnCount: 3 }
411 'id': 3, 'role': 'row',
415 'id': 4, 'role': 'cell',
416 'intAttributes': { 'tableCellColumnIndex': 0,
417 'tableCellColumnSpan': 2,
418 'tableCellRowIndex': 0,
419 'tableCellRowSpan': 1 },
423 'id': 5, 'role': 'cell',
424 'intAttributes': { 'tableCellColumnIndex': 2,
425 'tableCellColumnSpan': 1,
426 'tableCellRowIndex': 0,
427 'tableCellRowSpan': 2 },
431 'id': 6, 'role': 'row',
435 'id': 7, 'role': 'cell',
436 'intAttributes': { 'tableCellColumnIndex': 0,
437 'tableCellColumnSpan': 1,
438 'tableCellRowIndex': 1,
439 'tableCellRowSpan': 1 },
443 'id': 8, 'role': 'cell',
444 'intAttributes': { 'tableCellColumnIndex': 1,
445 'tableCellColumnSpan': 1,
446 'tableCellRowIndex': 1,
447 'tableCellRowSpan': 1 },
452 var tree = new AutomationRootNode();
454 assertTrue(privates(tree).impl.unserialize(update));
456 console.log(e.stack);
458 var TableMixinAttributes = {
462 for (var attribute in TableMixinAttributes)
463 assertFalse(attribute in tree);
465 var TableCellMixinAttributes = {
466 tableCellColumnIndex: 0,
467 tableCellColumnSpan: 1,
468 tableCellRowIndex: 0,
471 for (var attribute in TableCellMixinAttributes)
472 assertFalse(attribute in tree);
474 var table = tree.firstChild;
475 assertEq(2, table.tableRowCount);
476 assertEq(3, table.tableColumnCount);
478 var row1 = table.firstChild;
479 var cell1 = row1.firstChild;
480 assertEq(0, cell1.tableCellColumnIndex);
481 assertEq(2, cell1.tableCellColumnSpan);
482 assertEq(0, cell1.tableCellRowIndex);
483 assertEq(1, cell1.tableCellRowSpan);
485 var cell2 = cell1.nextSibling;
486 assertEq(2, cell2.tableCellColumnIndex);
487 assertEq(1, cell2.tableCellColumnSpan);
488 assertEq(0, cell2.tableCellRowIndex);
489 assertEq(2, cell2.tableCellRowSpan);
491 var row2 = row1.nextSibling;
492 var cell3 = row2.firstChild;
493 assertEq(0, cell3.tableCellColumnIndex);
494 assertEq(1, cell3.tableCellColumnSpan);
495 assertEq(1, cell3.tableCellRowIndex);
496 assertEq(1, cell3.tableCellRowSpan);
498 var cell4 = cell3.nextSibling;
499 assertEq(1, cell4.tableCellColumnIndex);
500 assertEq(1, cell4.tableCellColumnSpan);
501 assertEq(1, cell4.tableCellRowIndex);
502 assertEq(1, cell4.tableCellRowSpan);
508 chrome.test.runTests(tests);