| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 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 function initialize_DumpAccessibilityNodesTest() { | |
| 6 | |
| 7 var nodeInfo = {}; | |
| 8 InspectorTest.trackGetChildNodesEvents(nodeInfo); | |
| 9 | |
| 10 InspectorTest.dumpAccessibilityNodesBySelectorAndCompleteTest = function(selecto
r, fetchRelatives, msg) { | |
| 11 if (msg.error) { | |
| 12 InspectorTest.log(msg.error.message); | |
| 13 InspectorTest.completeTest(); | |
| 14 return; | |
| 15 } | |
| 16 | |
| 17 var rootNode = msg.result.root; | |
| 18 var rootNodeId = rootNode.nodeId; | |
| 19 InspectorTest.addNode(nodeInfo, rootNode); | |
| 20 | |
| 21 sendQuerySelectorAll(rootNodeId, selector) | |
| 22 .then((msg) => { return getAXNodes(msg, fetchRelatives || false) } ) | |
| 23 .then(() => { done(); }) | |
| 24 .then(() => { | |
| 25 InspectorTest.completeTest(); | |
| 26 }) | |
| 27 .catch((msg) => { InspectorTest.log("Error: " + JSON.stringify(msg)); }) | |
| 28 } | |
| 29 | |
| 30 function sendCommandPromise(command, params) | |
| 31 { | |
| 32 return new Promise(function(resolve, reject) { | |
| 33 InspectorTest.sendCommand(command, params, function(msg) { | |
| 34 if (msg.error) { | |
| 35 reject(msg.error); | |
| 36 return; | |
| 37 } | |
| 38 | |
| 39 resolve(msg); | |
| 40 }) | |
| 41 }); | |
| 42 } | |
| 43 | |
| 44 function done() | |
| 45 { | |
| 46 sendCommandPromise("Runtime.evaluate", { expression: "done();" }); | |
| 47 } | |
| 48 | |
| 49 function sendQuerySelectorAll(nodeId, selector) | |
| 50 { | |
| 51 return sendCommandPromise("DOM.querySelectorAll", { "nodeId": nodeId, "selec
tor": | |
| 52 selector }); | |
| 53 } | |
| 54 | |
| 55 function getAXNodes(msg, fetchRelatives) | |
| 56 { | |
| 57 var promise = Promise.resolve(); | |
| 58 if (!msg.result || !msg.result.nodeIds) { | |
| 59 InspectorTest.log("Unexpected result: " + JSON.stringify(msg)); | |
| 60 InspectorTest.completeTest(); | |
| 61 } | |
| 62 msg.result.nodeIds.forEach((id) => { | |
| 63 if (fetchRelatives) { | |
| 64 promise = promise.then(() => { | |
| 65 return sendCommandPromise("Accessibility.getPartialAXTree", { "n
odeId": id, "fetchRelatives": true }); | |
| 66 }); | |
| 67 promise = promise.then((msg) => { return rewriteRelatedNodes(msg, id
); }) | |
| 68 .then((msg) => { return dumpTreeStructure(msg); }); | |
| 69 | |
| 70 } | |
| 71 promise = promise.then(() => { return sendCommandPromise("Accessibility.
getPartialAXTree", { "nodeId": id, "fetchRelatives": false }); }) | |
| 72 .then((msg) => { return rewriteRelatedNodes(msg, id); }
) | |
| 73 .then((msg) => { return dumpNode(msg); }); | |
| 74 | |
| 75 }); | |
| 76 return promise; | |
| 77 } | |
| 78 | |
| 79 function describeDomNode(nodeData) | |
| 80 { | |
| 81 var description = nodeData.nodeName.toLowerCase(); | |
| 82 switch (nodeData.nodeType) { | |
| 83 case Node.ELEMENT_NODE: | |
| 84 var p = nodeData.attributes.indexOf("id"); | |
| 85 if (p >= 0) | |
| 86 description += "#" + nodeData.attributes[p + 1]; | |
| 87 } | |
| 88 return description; | |
| 89 } | |
| 90 | |
| 91 function rewriteBackendDomNodeId(axNode, selectedNodeId, promises) | |
| 92 { | |
| 93 if (!("backendDOMNodeId" in axNode)) | |
| 94 return; | |
| 95 | |
| 96 function rewriteBackendDomNodeIdPromise(resolve, reject) | |
| 97 { | |
| 98 if (!("backendDOMNodeId" in axNode)) { | |
| 99 resolve(); | |
| 100 return; | |
| 101 } | |
| 102 var backendDOMNodeId = axNode.backendDOMNodeId; | |
| 103 | |
| 104 function onDomNodeResolved(backendDOMNodeId, message) | |
| 105 { | |
| 106 if (!message.result || !message.result.nodeIds) { | |
| 107 InspectorTest.log("Unexpected result for pushNodesByBackendIdsTo
Frontend: " + JSON.stringify(message)); | |
| 108 InspectorTest.completeTest(); | |
| 109 return; | |
| 110 } | |
| 111 var nodeId = message.result.nodeIds[0]; | |
| 112 if (!(nodeId in nodeInfo)) { | |
| 113 axNode.domNode = "[NODE NOT FOUND]"; | |
| 114 resolve(); | |
| 115 return; | |
| 116 } | |
| 117 var domNode = nodeInfo[nodeId]; | |
| 118 delete axNode.backendDOMNodeId; | |
| 119 axNode.domNode = describeDomNode(domNode); | |
| 120 if (nodeId === selectedNodeId) | |
| 121 axNode.selected = true; | |
| 122 resolve(); | |
| 123 } | |
| 124 | |
| 125 var params = { "backendNodeIds": [ backendDOMNodeId ] }; | |
| 126 InspectorTest.sendCommand("DOM.pushNodesByBackendIdsToFrontend", params
, onDomNodeResolved.bind(null, backendDOMNodeId)); | |
| 127 } | |
| 128 promises.push(new Promise(rewriteBackendDomNodeIdPromise)); | |
| 129 } | |
| 130 | |
| 131 function rewriteRelatedNode(relatedNode) | |
| 132 { | |
| 133 function rewriteRelatedNodePromise(resolve, reject) | |
| 134 { | |
| 135 if (!("backendDOMNodeId" in relatedNode)) { | |
| 136 reject("Could not find backendDOMNodeId in " + JSON.stringify(relate
dNode)); | |
| 137 return; | |
| 138 } | |
| 139 var backendDOMNodeId = relatedNode.backendDOMNodeId; | |
| 140 | |
| 141 function onNodeResolved(backendDOMNodeId, message) | |
| 142 { | |
| 143 if (!message.result || !message.result.nodeIds) { | |
| 144 InspectorTest.log("Unexpected result for pushNodesByBackendIdsTo
Frontend: " + JSON.stringify(message)); | |
| 145 InspectorTest.completeTest(); | |
| 146 return; | |
| 147 } | |
| 148 var nodeId = message.result.nodeIds[0]; | |
| 149 if (!(nodeId in nodeInfo)) { | |
| 150 relatedNode.nodeResult = "[NODE NOT FOUND]"; | |
| 151 resolve(); | |
| 152 return; | |
| 153 } | |
| 154 var domNode = nodeInfo[nodeId]; | |
| 155 delete relatedNode.backendDOMNodeId; | |
| 156 relatedNode.nodeResult = describeDomNode(domNode); | |
| 157 resolve(); | |
| 158 } | |
| 159 var params = { "backendNodeIds": [ backendDOMNodeId ] }; | |
| 160 InspectorTest.sendCommand("DOM.pushNodesByBackendIdsToFrontend", params,
onNodeResolved.bind(null, backendDOMNodeId)); | |
| 161 | |
| 162 } | |
| 163 return new Promise(rewriteRelatedNodePromise); | |
| 164 } | |
| 165 | |
| 166 function checkExists(path, obj) | |
| 167 { | |
| 168 var pathComponents = path.split("."); | |
| 169 var currentPath = []; | |
| 170 var currentObject = obj; | |
| 171 for (var component of pathComponents) { | |
| 172 var isArray = false; | |
| 173 var index = -1; | |
| 174 var matches = component.match(/(\w+)\[(\d+)\]/); | |
| 175 if (matches) { | |
| 176 isArray = true; | |
| 177 component = matches[1]; | |
| 178 index = Number.parseInt(matches[2], 10); | |
| 179 } | |
| 180 currentPath.push(component); | |
| 181 if (!(component in currentObject)) { | |
| 182 InspectorTest.log("Could not find " + currentPath.join(".") + " in "
+ JSON.stringify(obj, null, " ")); | |
| 183 InspectorTest.completeTest(); | |
| 184 } | |
| 185 if (isArray) | |
| 186 currentObject = currentObject[component][index]; | |
| 187 else | |
| 188 currentObject = currentObject[component]; | |
| 189 } | |
| 190 return true; | |
| 191 } | |
| 192 | |
| 193 function check(condition, errorMsg, obj) | |
| 194 { | |
| 195 if (condition) | |
| 196 return true; | |
| 197 throw new Error(errorMsg + " in " + JSON.stringify(obj, null, " ")); | |
| 198 } | |
| 199 | |
| 200 function rewriteRelatedNodeValue(value, promises) | |
| 201 { | |
| 202 checkExists("relatedNodes", value); | |
| 203 var relatedNodeArray = value.relatedNodes; | |
| 204 check(Array.isArray(relatedNodeArray), "relatedNodes should be an array", JS
ON.stringify(value)); | |
| 205 for (var relatedNode of relatedNodeArray) { | |
| 206 promises.push(rewriteRelatedNode(relatedNode)); | |
| 207 } | |
| 208 } | |
| 209 | |
| 210 function rewriteRelatedNodes(msg, nodeId) | |
| 211 { | |
| 212 if (msg.error) { | |
| 213 throw new Error(msg.error.message); | |
| 214 } | |
| 215 | |
| 216 var promises = []; | |
| 217 for (var node of msg.result.nodes) { | |
| 218 if (node.ignored) { | |
| 219 checkExists("ignoredReasons", node); | |
| 220 var properties = node.ignoredReasons; | |
| 221 } else { | |
| 222 checkExists("properties", node); | |
| 223 var properties = node.properties; | |
| 224 } | |
| 225 if (node.name && node.name.sources) { | |
| 226 for (var source of node.name.sources) { | |
| 227 var value; | |
| 228 if (source.value) | |
| 229 value = source.value; | |
| 230 if (source.attributeValue) | |
| 231 value = source.attributeValue; | |
| 232 if (!value) | |
| 233 continue; | |
| 234 if (value.type === "idrefList" || | |
| 235 value.type === "idref" || | |
| 236 value.type === "nodeList") | |
| 237 rewriteRelatedNodeValue(value, promises); | |
| 238 } | |
| 239 } | |
| 240 for (var property of properties) { | |
| 241 if (property.value.type === "idrefList" || | |
| 242 property.value.type === "idref" || | |
| 243 property.value.type === "nodeList") | |
| 244 rewriteRelatedNodeValue(property.value, promises); | |
| 245 } | |
| 246 rewriteBackendDomNodeId(node, nodeId, promises); | |
| 247 } | |
| 248 return Promise.all(promises).then(() => { return msg; }); | |
| 249 } | |
| 250 | |
| 251 function dumpNode(msg) | |
| 252 { | |
| 253 function stripIds(key, value) | |
| 254 { | |
| 255 var stripKeys = ["id", "backendDOMNodeId", "nodeId", "parentId"]; | |
| 256 if (stripKeys.indexOf(key) !== -1) | |
| 257 return "<" + typeof(value) + ">"; | |
| 258 var deleteKeys = ["selected"]; | |
| 259 if (deleteKeys.indexOf(key) !== -1) | |
| 260 return undefined; | |
| 261 return value; | |
| 262 } | |
| 263 if (!msg.result || !msg.result.nodes || msg.result.nodes.length !== 1) { | |
| 264 InspectorTest.log("Expected exactly one node in " + JSON.stringify(msg,
null, " ")); | |
| 265 return; | |
| 266 } | |
| 267 InspectorTest.log(JSON.stringify(msg.result.nodes[0], stripIds, " ")); | |
| 268 } | |
| 269 | |
| 270 function dumpTreeStructure(msg) | |
| 271 { | |
| 272 function printNodeAndChildren(node, leadingSpace) | |
| 273 { | |
| 274 leadingSpace = leadingSpace || ""; | |
| 275 var string = leadingSpace; | |
| 276 if (node.selected) | |
| 277 string += "*"; | |
| 278 if (node.role) | |
| 279 string += node.role.value; | |
| 280 else | |
| 281 string += "<no role>"; | |
| 282 string += (node.name && node.name.value !== "" ? " \"" + node.name.value
+ "\"" : ""); | |
| 283 if (node.children) { | |
| 284 for (var child of node.children) | |
| 285 string += "\n" + printNodeAndChildren(child, leadingSpace + " "
); | |
| 286 } | |
| 287 return string; | |
| 288 } | |
| 289 | |
| 290 var rawMsg = JSON.stringify(msg, null, " "); | |
| 291 var nodeMap = {}; | |
| 292 if ("result" in msg && "nodes" in msg.result) { | |
| 293 for (var node of msg.result.nodes) | |
| 294 nodeMap[node.nodeId] = node; | |
| 295 } | |
| 296 for (var nodeId in nodeMap) { | |
| 297 var node = nodeMap[nodeId]; | |
| 298 if (node.childIds) { | |
| 299 node.children = []; | |
| 300 for (var i = 0; i < node.childIds.length && node.childIds.length > 0
;) { | |
| 301 var childId = node.childIds[i]; | |
| 302 if (childId in nodeMap) { | |
| 303 var child = nodeMap[childId]; | |
| 304 child.parentId = nodeId; | |
| 305 node.children.push(child); | |
| 306 | |
| 307 node.childIds.splice(i, 1); | |
| 308 } else { | |
| 309 node.childIds[i] = "<string>"; | |
| 310 i++; | |
| 311 } | |
| 312 } | |
| 313 if (!node.childIds.length) | |
| 314 delete node.childIds; | |
| 315 if (!node.children.length) | |
| 316 delete node.children; | |
| 317 } | |
| 318 } | |
| 319 var rootNode = Object.values(nodeMap).find((node) => !("parentId" in node)); | |
| 320 for (var node of Object.values(nodeMap)) | |
| 321 delete node.parentId; | |
| 322 | |
| 323 InspectorTest.log("\n" + printNodeAndChildren(rootNode)); | |
| 324 } | |
| 325 | |
| 326 } | |
| OLD | NEW |