<!DOCTYPE html> <html> <head> <title>Test document root content mutations</title> <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> <script type="application/javascript" src="../common.js"></script> <script type="application/javascript" src="../role.js"></script> <script type="application/javascript" src="../states.js"></script> <script type="application/javascript" src="../events.js"></script> <script type="application/javascript"> //////////////////////////////////////////////////////////////////////////// // Helpers function getDocNode(aID) { return getNode(aID).contentDocument; } function getDocChildNode(aID) { return getDocNode(aID).body.firstChild; } function rootContentReplaced(aID, aTextName, aRootContentRole) { this.eventSeq = [ new invokerChecker(EVENT_SHOW, getDocChildNode, aID), new invokerChecker(EVENT_REORDER, getDocNode, aID) ]; this.finalCheck = function rootContentReplaced_finalCheck() { var tree = { role: aRootContentRole || ROLE_DOCUMENT, children: [ { role: ROLE_TEXT_LEAF, name: aTextName } ] }; testAccessibleTree(getDocNode(aID), tree); } } function rootContentRemoved(aID) { this.eventSeq = [ new invokerChecker(EVENT_HIDE, null), new invokerChecker(EVENT_REORDER, getDocNode, aID) ]; this.preinvoke = function rootContentRemoved_preinvoke() { // Set up target for hide event before we invoke. var text = getAccessible(getAccessible(getDocNode(aID)).firstChild); this.eventSeq[0].target = text; } this.finalCheck = function rootContentRemoved_finalCheck() { var tree = { role: ROLE_DOCUMENT, children: [ ] }; testAccessibleTree(getDocNode(aID), tree); } } function rootContentInserted(aID, aTextName) { this.eventSeq = [ new invokerChecker(EVENT_SHOW, getDocChildNode, aID), new invokerChecker(EVENT_REORDER, getDocNode, aID) ]; this.finalCheck = function rootContentInserted_finalCheck() { var tree = { role: ROLE_DOCUMENT, children: [ { role: ROLE_TEXT_LEAF, name: aTextName } ] }; testAccessibleTree(getDocNode(aID), tree); } } //////////////////////////////////////////////////////////////////////////// // Invokers function writeIFrameDoc(aID) { this.__proto__ = new rootContentReplaced(aID, "hello"); this.invoke = function writeIFrameDoc_invoke() { var docNode = getDocNode(aID); // We can't use open/write/close outside of iframe document because of // security error. var script = docNode.createElement("script"); script.textContent = "document.open(); document.write('hello'); document.close();"; docNode.body.appendChild(script); } this.getID = function writeIFrameDoc_getID() { return "write document"; } } /** * Replace HTML element. */ function replaceIFrameHTMLElm(aID) { this.eventSeq = [ new invokerChecker(EVENT_SHOW, getDocChildNode, aID), new invokerChecker(EVENT_REORDER, getDocNode, aID) ]; this.invoke = function replaceIFrameHTMLElm_invoke() { var docNode = getDocNode(aID); var newHTMLNode = docNode.createElement("html"); newHTMLNode.innerHTML = `<body><p>New Wave</p></body`; docNode.replaceChild(newHTMLNode, docNode.documentElement); } this.finalCheck = function replaceIFrameHTMLElm_finalCheck() { var tree = { role: ROLE_DOCUMENT, children: [ { role: ROLE_PARAGRAPH, children: [ { role: ROLE_TEXT_LEAF, name: 'New Wave' } ] } ] }; testAccessibleTree(getDocNode(aID), tree); } this.getID = function replaceIFrameHTMLElm_getID() { return "replace HTML element"; } } /** * Replace HTML body on new body having ARIA role. */ function replaceIFrameBody(aID) { this.__proto__ = new rootContentReplaced(aID, "New Hello"); this.invoke = function replaceIFrameBody_invoke() { var docNode = getDocNode(aID); var newBodyNode = docNode.createElement("body"); var newTextNode = docNode.createTextNode("New Hello"); newBodyNode.appendChild(newTextNode); docNode.documentElement.replaceChild(newBodyNode, docNode.body); } this.getID = function replaceIFrameBody_getID() { return "replace body"; } } /** * Replace HTML body on new body having ARIA role. */ function replaceIFrameBodyOnARIARoleBody(aID) { this.__proto__ = new rootContentReplaced(aID, "New Hello", ROLE_PUSHBUTTON); this.invoke = function replaceIFrameBodyOnARIARoleBody_invoke() { var docNode = getDocNode(aID); var newBodyNode = docNode.createElement("body"); var newTextNode = docNode.createTextNode("New Hello"); newBodyNode.appendChild(newTextNode); newBodyNode.setAttribute("role", "button"); docNode.documentElement.replaceChild(newBodyNode, docNode.body); } this.getID = function replaceIFrameBodyOnARIARoleBody_getID() { return "replace body on body having ARIA role"; } } /** * Open/close document pair. */ function openIFrameDoc(aID) { this.__proto__ = new rootContentRemoved(aID); this.invoke = function openIFrameDoc_invoke() { this.preinvoke(); // Open document. var docNode = getDocNode(aID); var script = docNode.createElement("script"); script.textContent = "function closeMe() { document.write('Works?'); document.close(); } window.closeMe = closeMe; document.open();"; docNode.body.appendChild(script); } this.getID = function openIFrameDoc_getID() { return "open document"; } } function closeIFrameDoc(aID) { this.__proto__ = new rootContentInserted(aID, "Works?"); this.invoke = function closeIFrameDoc_invoke() { // Write and close document. getDocNode(aID).write('Works?'); getDocNode(aID).close(); } this.getID = function closeIFrameDoc_getID() { return "close document"; } } /** * Remove/insert HTML element pair. */ function removeHTMLFromIFrameDoc(aID) { this.__proto__ = new rootContentRemoved(aID); this.invoke = function removeHTMLFromIFrameDoc_invoke() { this.preinvoke(); // Remove HTML element. var docNode = getDocNode(aID); docNode.removeChild(docNode.firstChild); } this.getID = function removeHTMLFromIFrameDoc_getID() { return "remove HTML element"; } } function insertHTMLToIFrameDoc(aID) { this.__proto__ = new rootContentInserted(aID, "Haha"); this.invoke = function insertHTMLToIFrameDoc_invoke() { // Insert HTML element. var docNode = getDocNode(aID); var html = docNode.createElement("html"); var body = docNode.createElement("body"); var text = docNode.createTextNode("Haha"); body.appendChild(text); html.appendChild(body); docNode.appendChild(html); } this.getID = function insertHTMLToIFrameDoc_getID() { return "insert HTML element document"; } } /** * Remove/insert HTML body pair. */ function removeBodyFromIFrameDoc(aID) { this.__proto__ = new rootContentRemoved(aID); this.invoke = function removeBodyFromIFrameDoc_invoke() { this.preinvoke(); // Remove body element. var docNode = getDocNode(aID); docNode.documentElement.removeChild(docNode.body); } this.getID = function removeBodyFromIFrameDoc_getID() { return "remove body element"; } } function insertElmUnderDocElmWhileBodyMissed(aID) { this.docNode = null; this.inputNode = null; function getInputNode() { return this.inputNode; } this.eventSeq = [ new invokerChecker(EVENT_SHOW, getInputNode.bind(this)), new invokerChecker(EVENT_REORDER, getDocNode, aID) ]; this.invoke = function invoke() { this.docNode = getDocNode(aID); this.inputNode = this.docNode.createElement("input"); this.docNode.documentElement.appendChild(this.inputNode); } this.finalCheck = function finalCheck() { var tree = { DOCUMENT: [ { ENTRY: [ ] } ] }; testAccessibleTree(this.docNode, tree); // Remove aftermath of this test before next test starts. this.docNode.documentElement.removeChild(this.inputNode); } this.getID = function getID() { return "Insert element under document element while body is missed."; } } function insertBodyToIFrameDoc(aID) { this.__proto__ = new rootContentInserted(aID, "Yo ho ho i butylka roma!"); this.invoke = function insertBodyToIFrameDoc_invoke() { // Insert body element. var docNode = getDocNode(aID); var body = docNode.createElement("body"); var text = docNode.createTextNode("Yo ho ho i butylka roma!"); body.appendChild(text); docNode.documentElement.appendChild(body); } this.getID = function insertBodyToIFrameDoc_getID() { return "insert body element"; } } function changeSrc(aID) { this.containerNode = getNode(aID); this.eventSeq = [ new invokerChecker(EVENT_REORDER, this.containerNode) ]; this.invoke = function changeSrc_invoke() { this.containerNode.src = "data:text/html,<html><input></html>"; } this.finalCheck = function changeSrc_finalCheck() { var tree = { INTERNAL_FRAME: [ { DOCUMENT: [ { ENTRY: [ ] } ] } ] }; testAccessibleTree(this.containerNode, tree); } this.getID = function changeSrc_getID() { return "change src on iframe"; } } //////////////////////////////////////////////////////////////////////////// // Test //gA11yEventDumpToConsole = true; //enableLogging('tree,verbose'); var gQueue = null; function doTest() { gQueue = new eventQueue(); gQueue.push(new writeIFrameDoc("iframe")); gQueue.push(new replaceIFrameHTMLElm("iframe")); gQueue.push(new replaceIFrameBody("iframe")); gQueue.push(new openIFrameDoc("iframe")); gQueue.push(new closeIFrameDoc("iframe")); gQueue.push(new removeHTMLFromIFrameDoc("iframe")); gQueue.push(new insertHTMLToIFrameDoc("iframe")); gQueue.push(new removeBodyFromIFrameDoc("iframe")); gQueue.push(new insertElmUnderDocElmWhileBodyMissed("iframe")); gQueue.push(new insertBodyToIFrameDoc("iframe")); gQueue.push(new changeSrc("iframe")); gQueue.push(new replaceIFrameBodyOnARIARoleBody("iframe")); gQueue.invoke(); // SimpleTest.finish() will be called in the end } SimpleTest.waitForExplicitFinish(); addA11yLoadEvent(doTest); </script> </head> <body> <a target="_blank" title="Update accessible tree when root element is changed" href="https://bugzilla.mozilla.org/show_bug.cgi?id=606082">Mozilla Bug 606082</a> <a target="_blank" title="Elements inserted outside the body aren't accessible" href="https://bugzilla.mozilla.org/show_bug.cgi?id=608887">Mozilla Bug 608887</a> <a target="_blank" title="Reorder event for document must be fired after document initial tree creation" href="https://bugzilla.mozilla.org/show_bug.cgi?id=669263">Mozilla Bug 669263</a> <a target="_blank" title="Changing the HTML body doesn't pick up ARIA role" href="https://bugzilla.mozilla.org/show_bug.cgi?id=818407">Mozilla Bug 818407</a> <p id="display"></p> <div id="content" style="display: none"></div> <pre id="test"> </pre> <iframe id="iframe"></iframe> <div id="eventdump"></div> </body> </html>