test_doc.html (12742B)
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <title>Test document root content mutations</title> 6 <link rel="stylesheet" type="text/css" 7 href="chrome://mochikit/content/tests/SimpleTest/test.css" /> 8 9 <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> 10 11 <script type="application/javascript" 12 src="../common.js"></script> 13 <script type="application/javascript" 14 src="../role.js"></script> 15 <script type="application/javascript" 16 src="../states.js"></script> 17 <script type="application/javascript" 18 src="../events.js"></script> 19 20 <script type="application/javascript"> 21 22 // ////////////////////////////////////////////////////////////////////////// 23 // Helpers 24 25 function getDocNode(aID) { 26 return getNode(aID).contentDocument; 27 } 28 function getDocChildNode(aID) { 29 return getDocNode(aID).body.firstChild; 30 } 31 32 function rootContentReplaced(aID, aTextName, aRootContentRole) { 33 this.eventSeq = [ 34 new invokerChecker(EVENT_SHOW, getDocChildNode, aID), 35 new invokerChecker(EVENT_REORDER, getDocNode, aID), 36 ]; 37 38 this.finalCheck = function rootContentReplaced_finalCheck() { 39 var tree = { 40 role: aRootContentRole || ROLE_DOCUMENT, 41 children: [ 42 { 43 role: ROLE_TEXT_LEAF, 44 name: aTextName, 45 }, 46 ], 47 }; 48 testAccessibleTree(getDocNode(aID), tree); 49 }; 50 } 51 52 function rootContentRemoved(aID) { 53 this.eventSeq = [ 54 new invokerChecker(EVENT_HIDE, null), 55 new invokerChecker(EVENT_REORDER, getDocNode, aID), 56 ]; 57 58 this.preinvoke = function rootContentRemoved_preinvoke() { 59 // Set up target for hide event before we invoke. 60 var text = getAccessible(getAccessible(getDocNode(aID)).firstChild); 61 this.eventSeq[0].target = text; 62 }; 63 64 this.finalCheck = function rootContentRemoved_finalCheck() { 65 var tree = { 66 role: ROLE_DOCUMENT, 67 children: [ ], 68 }; 69 testAccessibleTree(getDocNode(aID), tree); 70 }; 71 } 72 73 function rootContentInserted(aID, aTextName) { 74 this.eventSeq = [ 75 new invokerChecker(EVENT_SHOW, getDocChildNode, aID), 76 new invokerChecker(EVENT_REORDER, getDocNode, aID), 77 ]; 78 79 this.finalCheck = function rootContentInserted_finalCheck() { 80 var tree = { 81 role: ROLE_DOCUMENT, 82 children: [ 83 { 84 role: ROLE_TEXT_LEAF, 85 name: aTextName, 86 }, 87 ], 88 }; 89 testAccessibleTree(getDocNode(aID), tree); 90 }; 91 } 92 93 // ////////////////////////////////////////////////////////////////////////// 94 // Invokers 95 96 function writeIFrameDoc(aID) { 97 this.__proto__ = new rootContentReplaced(aID, "hello"); 98 99 this.invoke = function writeIFrameDoc_invoke() { 100 var docNode = getDocNode(aID); 101 102 // We can't use open/write/close outside of iframe document because of 103 // security error. 104 var script = docNode.createElement("script"); 105 script.textContent = "document.open(); document.write('hello'); document.close();"; 106 docNode.body.appendChild(script); 107 }; 108 109 this.getID = function writeIFrameDoc_getID() { 110 return "write document"; 111 }; 112 } 113 114 /** 115 * Replace HTML element. 116 */ 117 function replaceIFrameHTMLElm(aID) { 118 this.eventSeq = [ 119 new invokerChecker(EVENT_SHOW, getDocChildNode, aID), 120 new invokerChecker(EVENT_REORDER, getDocNode, aID), 121 ]; 122 123 this.invoke = function replaceIFrameHTMLElm_invoke() { 124 var docNode = getDocNode(aID); 125 var newHTMLNode = docNode.createElement("html"); 126 newHTMLNode.innerHTML = `<body><p>New Wave</p></body`; 127 docNode.replaceChild(newHTMLNode, docNode.documentElement); 128 }; 129 130 this.finalCheck = function replaceIFrameHTMLElm_finalCheck() { 131 var tree = { 132 role: ROLE_DOCUMENT, 133 children: [ 134 { 135 role: ROLE_PARAGRAPH, 136 children: [ 137 { 138 role: ROLE_TEXT_LEAF, 139 name: "New Wave", 140 }, 141 ], 142 }, 143 ], 144 }; 145 testAccessibleTree(getDocNode(aID), tree); 146 }; 147 148 this.getID = function replaceIFrameHTMLElm_getID() { 149 return "replace HTML element"; 150 }; 151 } 152 153 /** 154 * Replace HTML body on new body having ARIA role. 155 */ 156 function replaceIFrameBody(aID) { 157 this.__proto__ = new rootContentReplaced(aID, "New Hello"); 158 159 this.invoke = function replaceIFrameBody_invoke() { 160 var docNode = getDocNode(aID); 161 var newBodyNode = docNode.createElement("body"); 162 var newTextNode = docNode.createTextNode("New Hello"); 163 newBodyNode.appendChild(newTextNode); 164 docNode.documentElement.replaceChild(newBodyNode, docNode.body); 165 }; 166 167 this.getID = function replaceIFrameBody_getID() { 168 return "replace body"; 169 }; 170 } 171 172 /** 173 * Replace HTML body on new body having ARIA role. 174 */ 175 function replaceIFrameBodyOnARIARoleBody(aID) { 176 this.__proto__ = new rootContentReplaced(aID, "New Hello", 177 ROLE_APPLICATION); 178 179 this.invoke = function replaceIFrameBodyOnARIARoleBody_invoke() { 180 var docNode = getDocNode(aID); 181 var newBodyNode = docNode.createElement("body"); 182 var newTextNode = docNode.createTextNode("New Hello"); 183 newBodyNode.appendChild(newTextNode); 184 newBodyNode.setAttribute("role", "application"); 185 docNode.documentElement.replaceChild(newBodyNode, docNode.body); 186 }; 187 188 this.getID = function replaceIFrameBodyOnARIARoleBody_getID() { 189 return "replace body on body having ARIA role"; 190 }; 191 } 192 193 /** 194 * Open/close document pair. 195 */ 196 function openIFrameDoc(aID) { 197 this.__proto__ = new rootContentRemoved(aID); 198 199 this.invoke = function openIFrameDoc_invoke() { 200 this.preinvoke(); 201 202 // Open document. 203 var docNode = getDocNode(aID); 204 var script = docNode.createElement("script"); 205 script.textContent = "function closeMe() { document.write('Works?'); document.close(); } window.closeMe = closeMe; document.open();"; 206 docNode.body.appendChild(script); 207 }; 208 209 this.getID = function openIFrameDoc_getID() { 210 return "open document"; 211 }; 212 } 213 214 function closeIFrameDoc(aID) { 215 this.__proto__ = new rootContentInserted(aID, "Works?"); 216 217 this.invoke = function closeIFrameDoc_invoke() { 218 // Write and close document. 219 getDocNode(aID).write("Works?"); getDocNode(aID).close(); 220 }; 221 222 this.getID = function closeIFrameDoc_getID() { 223 return "close document"; 224 }; 225 } 226 227 /** 228 * Remove/insert HTML element pair. 229 */ 230 function removeHTMLFromIFrameDoc(aID) { 231 this.__proto__ = new rootContentRemoved(aID); 232 233 this.invoke = function removeHTMLFromIFrameDoc_invoke() { 234 this.preinvoke(); 235 236 // Remove HTML element. 237 var docNode = getDocNode(aID); 238 docNode.firstChild.remove(); 239 }; 240 241 this.getID = function removeHTMLFromIFrameDoc_getID() { 242 return "remove HTML element"; 243 }; 244 } 245 246 function insertHTMLToIFrameDoc(aID) { 247 this.__proto__ = new rootContentInserted(aID, "Haha"); 248 249 this.invoke = function insertHTMLToIFrameDoc_invoke() { 250 // Insert HTML element. 251 var docNode = getDocNode(aID); 252 var html = docNode.createElement("html"); 253 var body = docNode.createElement("body"); 254 var text = docNode.createTextNode("Haha"); 255 body.appendChild(text); 256 html.appendChild(body); 257 docNode.appendChild(html); 258 }; 259 260 this.getID = function insertHTMLToIFrameDoc_getID() { 261 return "insert HTML element document"; 262 }; 263 } 264 265 /** 266 * Remove/insert HTML body pair. 267 */ 268 function removeBodyFromIFrameDoc(aID) { 269 this.__proto__ = new rootContentRemoved(aID); 270 271 this.invoke = function removeBodyFromIFrameDoc_invoke() { 272 this.preinvoke(); 273 274 // Remove body element. 275 var docNode = getDocNode(aID); 276 docNode.documentElement.removeChild(docNode.body); 277 }; 278 279 this.getID = function removeBodyFromIFrameDoc_getID() { 280 return "remove body element"; 281 }; 282 } 283 284 function insertElmUnderDocElmWhileBodyMissed(aID) { 285 this.docNode = null; 286 this.inputNode = null; 287 288 function getInputNode() { return this.inputNode; } 289 290 this.eventSeq = [ 291 new invokerChecker(EVENT_SHOW, getInputNode.bind(this)), 292 new invokerChecker(EVENT_REORDER, getDocNode, aID), 293 ]; 294 295 this.invoke = function invoke() { 296 this.docNode = getDocNode(aID); 297 this.inputNode = this.docNode.createElement("input"); 298 this.docNode.documentElement.appendChild(this.inputNode); 299 }; 300 301 this.finalCheck = function finalCheck() { 302 var tree = 303 { DOCUMENT: [ 304 { ENTRY: [ ] }, 305 ] }; 306 testAccessibleTree(this.docNode, tree); 307 308 // Remove aftermath of this test before next test starts. 309 this.docNode.documentElement.removeChild(this.inputNode); 310 }; 311 312 this.getID = function getID() { 313 return "Insert element under document element while body is missed."; 314 }; 315 } 316 317 function insertBodyToIFrameDoc(aID) { 318 this.__proto__ = new rootContentInserted(aID, "Yo ho ho i butylka roma!"); 319 320 this.invoke = function insertBodyToIFrameDoc_invoke() { 321 // Insert body element. 322 var docNode = getDocNode(aID); 323 var body = docNode.createElement("body"); 324 var text = docNode.createTextNode("Yo ho ho i butylka roma!"); 325 body.appendChild(text); 326 docNode.documentElement.appendChild(body); 327 }; 328 329 this.getID = function insertBodyToIFrameDoc_getID() { 330 return "insert body element"; 331 }; 332 } 333 334 function changeSrc(aID) { 335 this.containerNode = getNode(aID); 336 337 this.eventSeq = [ 338 new invokerChecker(EVENT_REORDER, this.containerNode), 339 ]; 340 341 this.invoke = function changeSrc_invoke() { 342 this.containerNode.src = "data:text/html,<html><input></html>"; 343 }; 344 345 this.finalCheck = function changeSrc_finalCheck() { 346 var tree = 347 { INTERNAL_FRAME: [ 348 { DOCUMENT: [ 349 { ENTRY: [ ] }, 350 ] }, 351 ] }; 352 testAccessibleTree(this.containerNode, tree); 353 }; 354 355 this.getID = function changeSrc_getID() { 356 return "change src on iframe"; 357 }; 358 } 359 360 // ////////////////////////////////////////////////////////////////////////// 361 // Test 362 363 // gA11yEventDumpToConsole = true; 364 // enableLogging('tree,verbose'); 365 366 var gQueue = null; 367 368 function doTest() { 369 gQueue = new eventQueue(); 370 371 gQueue.push(new writeIFrameDoc("iframe")); 372 gQueue.push(new replaceIFrameHTMLElm("iframe")); 373 gQueue.push(new replaceIFrameBody("iframe")); 374 gQueue.push(new openIFrameDoc("iframe")); 375 gQueue.push(new closeIFrameDoc("iframe")); 376 gQueue.push(new removeHTMLFromIFrameDoc("iframe")); 377 gQueue.push(new insertHTMLToIFrameDoc("iframe")); 378 gQueue.push(new removeBodyFromIFrameDoc("iframe")); 379 gQueue.push(new insertElmUnderDocElmWhileBodyMissed("iframe")); 380 gQueue.push(new insertBodyToIFrameDoc("iframe")); 381 gQueue.push(new changeSrc("iframe")); 382 gQueue.push(new replaceIFrameBodyOnARIARoleBody("iframe")); 383 384 gQueue.invoke(); // SimpleTest.finish() will be called in the end 385 } 386 387 SimpleTest.waitForExplicitFinish(); 388 addA11yLoadEvent(doTest); 389 </script> 390 </head> 391 <body> 392 393 <a target="_blank" 394 title="Update accessible tree when root element is changed" 395 href="https://bugzilla.mozilla.org/show_bug.cgi?id=606082">Mozilla Bug 606082</a> 396 <a target="_blank" 397 title="Elements inserted outside the body aren't accessible" 398 href="https://bugzilla.mozilla.org/show_bug.cgi?id=608887">Mozilla Bug 608887</a> 399 <a target="_blank" 400 title="Reorder event for document must be fired after document initial tree creation" 401 href="https://bugzilla.mozilla.org/show_bug.cgi?id=669263">Mozilla Bug 669263</a> 402 <a target="_blank" 403 title="Changing the HTML body doesn't pick up ARIA role" 404 href="https://bugzilla.mozilla.org/show_bug.cgi?id=818407">Mozilla Bug 818407</a> 405 406 <p id="display"></p> 407 <div id="content" style="display: none"></div> 408 <pre id="test"> 409 </pre> 410 411 <iframe id="iframe"></iframe> 412 413 <div id="eventdump"></div> 414 </body> 415 </html>