summaryrefslogtreecommitdiffstats
path: root/accessible/tests/mochitest/treeupdate
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/tests/mochitest/treeupdate')
-rw-r--r--accessible/tests/mochitest/treeupdate/a11y.ini41
-rw-r--r--accessible/tests/mochitest/treeupdate/test_ariadialog.html119
-rw-r--r--accessible/tests/mochitest/treeupdate/test_ariaowns.html693
-rw-r--r--accessible/tests/mochitest/treeupdate/test_bug1040735.html42
-rw-r--r--accessible/tests/mochitest/treeupdate/test_bug1100602.html114
-rw-r--r--accessible/tests/mochitest/treeupdate/test_bug1175913.html105
-rw-r--r--accessible/tests/mochitest/treeupdate/test_bug1189277.html86
-rw-r--r--accessible/tests/mochitest/treeupdate/test_bug1276857.html143
-rw-r--r--accessible/tests/mochitest/treeupdate/test_bug852150.xhtml59
-rw-r--r--accessible/tests/mochitest/treeupdate/test_bug883708.xhtml33
-rw-r--r--accessible/tests/mochitest/treeupdate/test_bug884251.xhtml21
-rw-r--r--accessible/tests/mochitest/treeupdate/test_bug895082.html51
-rw-r--r--accessible/tests/mochitest/treeupdate/test_canvas.html92
-rw-r--r--accessible/tests/mochitest/treeupdate/test_colorpicker.xul150
-rw-r--r--accessible/tests/mochitest/treeupdate/test_contextmenu.xul317
-rw-r--r--accessible/tests/mochitest/treeupdate/test_cssoverflow.html143
-rw-r--r--accessible/tests/mochitest/treeupdate/test_deck.xul109
-rw-r--r--accessible/tests/mochitest/treeupdate/test_doc.html466
-rw-r--r--accessible/tests/mochitest/treeupdate/test_gencontent.html160
-rw-r--r--accessible/tests/mochitest/treeupdate/test_general.html150
-rw-r--r--accessible/tests/mochitest/treeupdate/test_hidden.html135
-rw-r--r--accessible/tests/mochitest/treeupdate/test_imagemap.html442
-rw-r--r--accessible/tests/mochitest/treeupdate/test_list.html152
-rw-r--r--accessible/tests/mochitest/treeupdate/test_list_editabledoc.html106
-rw-r--r--accessible/tests/mochitest/treeupdate/test_listbox.xul180
-rw-r--r--accessible/tests/mochitest/treeupdate/test_menu.xul128
-rw-r--r--accessible/tests/mochitest/treeupdate/test_menubutton.xul198
-rw-r--r--accessible/tests/mochitest/treeupdate/test_optgroup.html137
-rw-r--r--accessible/tests/mochitest/treeupdate/test_recreation.html155
-rw-r--r--accessible/tests/mochitest/treeupdate/test_select.html130
-rw-r--r--accessible/tests/mochitest/treeupdate/test_shutdown.xul132
-rw-r--r--accessible/tests/mochitest/treeupdate/test_table.html81
-rw-r--r--accessible/tests/mochitest/treeupdate/test_textleaf.html180
-rw-r--r--accessible/tests/mochitest/treeupdate/test_visibility.html437
-rw-r--r--accessible/tests/mochitest/treeupdate/test_whitespace.html187
35 files changed, 5874 insertions, 0 deletions
diff --git a/accessible/tests/mochitest/treeupdate/a11y.ini b/accessible/tests/mochitest/treeupdate/a11y.ini
new file mode 100644
index 000000000..d725ebff3
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/a11y.ini
@@ -0,0 +1,41 @@
+[DEFAULT]
+support-files =
+ !/accessible/tests/mochitest/*.js
+ !/accessible/tests/mochitest/letters.gif
+ !/accessible/tests/mochitest/moz.png
+
+[test_ariadialog.html]
+[test_ariaowns.html]
+[test_bug852150.xhtml]
+[test_bug883708.xhtml]
+[test_bug884251.xhtml]
+[test_bug895082.html]
+[test_bug1040735.html]
+[test_bug1100602.html]
+[test_bug1175913.html]
+[test_bug1189277.html]
+[test_bug1276857.html]
+[test_canvas.html]
+[test_colorpicker.xul]
+[test_contextmenu.xul]
+[test_cssoverflow.html]
+[test_deck.xul]
+[test_doc.html]
+[test_gencontent.html]
+[test_general.html]
+[test_hidden.html]
+[test_imagemap.html]
+skip-if = buildapp == "mulet"
+[test_list.html]
+[test_list_editabledoc.html]
+[test_listbox.xul]
+[test_menu.xul]
+[test_menubutton.xul]
+[test_optgroup.html]
+[test_recreation.html]
+[test_select.html]
+[test_shutdown.xul]
+[test_table.html]
+[test_textleaf.html]
+[test_visibility.html]
+[test_whitespace.html]
diff --git a/accessible/tests/mochitest/treeupdate/test_ariadialog.html b/accessible/tests/mochitest/treeupdate/test_ariadialog.html
new file mode 100644
index 000000000..559431626
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_ariadialog.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Table creation in ARIA dialog test</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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Invokers
+
+ function showARIADialog(aID)
+ {
+ this.node = getNode(aID);
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_SHOW, this.node)
+ ];
+
+ this.invoke = function showARIADialog_invoke()
+ {
+ getNode("dialog").style.display = "block";
+ getNode("table").style.visibility = "visible";
+ getNode("a").textContent = "link";
+ getNode("input").value = "hello";
+ getNode("input").focus();
+ }
+
+ this.finalCheck = function showARIADialog_finalCheck()
+ {
+ var tree = {
+ role: ROLE_DIALOG,
+ children: [
+ {
+ role: ROLE_PUSHBUTTON,
+ children: [ { role: ROLE_TEXT_LEAF } ]
+ },
+ {
+ role: ROLE_ENTRY
+ }
+ ]
+ };
+ testAccessibleTree(aID, tree);
+ }
+
+ this.getID = function showARIADialog_getID()
+ {
+ return "show ARIA dialog";
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Test
+
+ //gA11yEventDumpID = "eventdump"; // debug stuff
+ //gA11yEventDumpToConsole = true;
+
+ var gQueue = null;
+
+ function doTest()
+ {
+ //enableLogging("tree");
+ gQueue = new eventQueue();
+
+ // make the accessible an inaccessible
+ gQueue.push(new showARIADialog("dialog"));
+
+ gQueue.invoke(); // SimpleTest.finish() will be called in the end
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank"
+ title="Rework accessible tree update code"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=570275">
+ Mozilla Bug 570275
+ </a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <div id="dialog" role="dialog" style="display: none;">
+ <table id="table" role="presentation"
+ style="display: block; position: fixed; top: 88px; left: 312.5px; z-index: 10010; visibility: hidden;">
+ <tbody>
+ <tr>
+ <td role="presentation">
+ <div role="presentation">
+ <a id="a" role="button">text</a>
+ </div>
+ <input id="input">
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+ <div id="eventdump"></div>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_ariaowns.html b/accessible/tests/mochitest/treeupdate/test_ariaowns.html
new file mode 100644
index 000000000..44fc22a2d
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_ariaowns.html
@@ -0,0 +1,693 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>@aria-owns attribute testing</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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Invokers
+ ////////////////////////////////////////////////////////////////////////////
+
+ function changeARIAOwns()
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getNode("t1_button")),
+ // no hide for t1_subdiv because it is contained by hidden t1_checkbox
+ new invokerChecker(EVENT_HIDE, getNode("t1_checkbox")),
+ new invokerChecker(EVENT_SHOW, getNode("t1_checkbox")),
+ new invokerChecker(EVENT_SHOW, getNode("t1_button")),
+ new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
+ new invokerChecker(EVENT_REORDER, getNode("t1_container"))
+ ];
+
+ this.invoke = function setARIAOwns_invoke()
+ {
+ // children are swapped by ARIA owns
+ var tree =
+ { SECTION: [
+ { CHECKBUTTON: [
+ { SECTION: [] }
+ ] },
+ { PUSHBUTTON: [ ] }
+ ] };
+ testAccessibleTree("t1_container", tree);
+
+ getNode("t1_container").
+ setAttribute("aria-owns", "t1_button t1_subdiv");
+ }
+
+ this.finalCheck = function setARIAOwns_finalCheck()
+ {
+ // children are swapped again, button and subdiv are appended to
+ // the children.
+ var tree =
+ { SECTION: [
+ { CHECKBUTTON: [ ] }, // checkbox, native order
+ { PUSHBUTTON: [ ] }, // button, rearranged by ARIA own
+ { SECTION: [ ] } // subdiv from the subtree, ARIA owned
+ ] };
+ testAccessibleTree("t1_container", tree);
+ }
+
+ this.getID = function setARIAOwns_getID()
+ {
+ return "Change @aria-owns attribute";
+ }
+ }
+
+ function removeARIAOwns()
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getNode("t1_button")),
+ new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")),
+ new orderChecker(),
+ new asyncInvokerChecker(EVENT_SHOW, getNode("t1_button")),
+ new asyncInvokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
+ new orderChecker(),
+ new invokerChecker(EVENT_REORDER, getNode("t1_container")),
+ new unexpectedInvokerChecker(EVENT_REORDER, getNode("t1_checkbox"))
+ ];
+
+ this.invoke = function removeARIAOwns_invoke()
+ {
+ getNode("t1_container").removeAttribute("aria-owns");
+ }
+
+ this.finalCheck = function removeARIAOwns_finalCheck()
+ {
+ // children follow the DOM order
+ var tree =
+ { SECTION: [
+ { PUSHBUTTON: [ ] },
+ { CHECKBUTTON: [
+ { SECTION: [] }
+ ] }
+ ] };
+ testAccessibleTree("t1_container", tree);
+ }
+
+ this.getID = function removeARIAOwns_getID()
+ {
+ return "Remove @aria-owns attribute";
+ }
+ }
+
+ function setARIAOwns()
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getNode("t1_button")),
+ new invokerChecker(EVENT_HIDE, getNode("t1_subdiv")),
+ new invokerChecker(EVENT_SHOW, getNode("t1_button")),
+ new invokerChecker(EVENT_SHOW, getNode("t1_subdiv")),
+ new invokerChecker(EVENT_REORDER, getNode("t1_container"))
+ ];
+
+ this.invoke = function setARIAOwns_invoke()
+ {
+ getNode("t1_container").
+ setAttribute("aria-owns", "t1_button t1_subdiv");
+ }
+
+ this.finalCheck = function setARIAOwns_finalCheck()
+ {
+ // children are swapped again, button and subdiv are appended to
+ // the children.
+ var tree =
+ { SECTION: [
+ { CHECKBUTTON: [ ] }, // checkbox
+ { PUSHBUTTON: [ ] }, // button, rearranged by ARIA own
+ { SECTION: [ ] } // subdiv from the subtree, ARIA owned
+ ] };
+ testAccessibleTree("t1_container", tree);
+ }
+
+ this.getID = function setARIAOwns_getID()
+ {
+ return "Set @aria-owns attribute";
+ }
+ }
+
+ function addIdToARIAOwns()
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getNode("t1_group")),
+ new invokerChecker(EVENT_SHOW, getNode("t1_group")),
+ new invokerChecker(EVENT_REORDER, document)
+ ];
+
+ this.invoke = function addIdToARIAOwns_invoke()
+ {
+ getNode("t1_container").
+ setAttribute("aria-owns", "t1_button t1_subdiv t1_group");
+ }
+
+ this.finalCheck = function addIdToARIAOwns_finalCheck()
+ {
+ // children are swapped again, button and subdiv are appended to
+ // the children.
+ var tree =
+ { SECTION: [
+ { CHECKBUTTON: [ ] }, // t1_checkbox
+ { PUSHBUTTON: [ ] }, // button, t1_button
+ { SECTION: [ ] }, // subdiv from the subtree, t1_subdiv
+ { GROUPING: [ ] } // group from outside, t1_group
+ ] };
+ testAccessibleTree("t1_container", tree);
+ }
+
+ this.getID = function addIdToARIAOwns_getID()
+ {
+ return "Add id to @aria-owns attribute value";
+ }
+ }
+
+ function appendEl()
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_SHOW, getNode, "t1_child3"),
+ new invokerChecker(EVENT_REORDER, getNode("t1_container"))
+ ];
+
+ this.invoke = function appendEl_invoke()
+ {
+ var div = document.createElement("div");
+ div.setAttribute("id", "t1_child3");
+ div.setAttribute("role", "radio")
+ getNode("t1_container").appendChild(div);
+ }
+
+ this.finalCheck = function appendEl_finalCheck()
+ {
+ // children are invalidated, they includes aria-owns swapped kids and
+ // newly inserted child.
+ var tree =
+ { SECTION: [
+ { CHECKBUTTON: [ ] }, // existing explicit, t1_checkbox
+ { RADIOBUTTON: [ ] }, // new explicit, t1_child3
+ { PUSHBUTTON: [ ] }, // ARIA owned, t1_button
+ { SECTION: [ ] }, // ARIA owned, t1_subdiv
+ { GROUPING: [ ] } // ARIA owned, t1_group
+ ] };
+ testAccessibleTree("t1_container", tree);
+ }
+
+ this.getID = function appendEl_getID()
+ {
+ return "Append child under @aria-owns element";
+ }
+ }
+
+ function removeEl()
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getNode, "t1_checkbox"),
+ new invokerChecker(EVENT_SHOW, getNode, "t1_checkbox"),
+ new invokerChecker(EVENT_REORDER, getNode("t1_container"))
+ ];
+
+ this.invoke = function removeEl_invoke()
+ {
+ // remove a container of t1_subdiv
+ getNode("t1_span").parentNode.removeChild(getNode("t1_span"));
+ }
+
+ this.finalCheck = function removeEl_finalCheck()
+ {
+ // subdiv should go away
+ var tree =
+ { SECTION: [
+ { CHECKBUTTON: [ ] }, // explicit, t1_checkbox
+ { RADIOBUTTON: [ ] }, // explicit, t1_child3
+ { PUSHBUTTON: [ ] }, // ARIA owned, t1_button
+ { GROUPING: [ ] } // ARIA owned, t1_group
+ ] };
+ testAccessibleTree("t1_container", tree);
+ }
+
+ this.getID = function removeEl_getID()
+ {
+ return "Remove a container of ARIA owned element";
+ }
+ }
+
+ function removeId()
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getNode("t1_group")),
+ new invokerChecker(EVENT_SHOW, getNode("t1_group")),
+ new invokerChecker(EVENT_REORDER, document)
+ ];
+
+ this.invoke = function removeId_invoke()
+ {
+ getNode("t1_group").removeAttribute("id");
+ }
+
+ this.finalCheck = function removeId_finalCheck()
+ {
+ var tree =
+ { SECTION: [
+ { CHECKBUTTON: [ ] },
+ { RADIOBUTTON: [ ] },
+ { PUSHBUTTON: [ ] } // ARIA owned, t1_button
+ ] };
+ testAccessibleTree("t1_container", tree);
+ }
+
+ this.getID = function removeId_getID()
+ {
+ return "Remove ID from ARIA owned element";
+ }
+ }
+
+ function setId()
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getNode("t1_grouptmp")),
+ new invokerChecker(EVENT_SHOW, getNode("t1_grouptmp")),
+ new invokerChecker(EVENT_REORDER, document)
+ ];
+
+ this.invoke = function setId_invoke()
+ {
+ getNode("t1_grouptmp").setAttribute("id", "t1_group");
+ }
+
+ this.finalCheck = function setId_finalCheck()
+ {
+ var tree =
+ { SECTION: [
+ { CHECKBUTTON: [ ] },
+ { RADIOBUTTON: [ ] },
+ { PUSHBUTTON: [ ] }, // ARIA owned, t1_button
+ { GROUPING: [ ] } // ARIA owned, t1_group, previously t1_grouptmp
+ ] };
+ testAccessibleTree("t1_container", tree);
+ }
+
+ this.getID = function setId_getID()
+ {
+ return "Set ID that is referred by ARIA owns";
+ }
+ }
+
+ /**
+ * Remove an accessible DOM element containing an element referred by
+ * ARIA owns.
+ */
+ function removeA11eteiner()
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, getNode("t2_container1"))
+ ];
+
+ this.invoke = function removeA11eteiner_invoke()
+ {
+ var tree =
+ { SECTION: [
+ { CHECKBUTTON: [ ] } // ARIA owned, 't2_owned'
+ ] };
+ testAccessibleTree("t2_container1", tree);
+
+ getNode("t2_container2").removeChild(getNode("t2_container3"));
+ }
+
+ this.finalCheck = function removeA11eteiner_finalCheck()
+ {
+ var tree =
+ { SECTION: [
+ ] };
+ testAccessibleTree("t2_container1", tree);
+ }
+
+ this.getID = function removeA11eteiner_getID()
+ {
+ return "Remove an accessible DOM element containing an element referred by ARIA owns";
+ }
+ }
+
+ /**
+ * Steal an element from other ARIA owns element. This use case guarantees
+ * that result of setAttribute/removeAttribute doesn't depend on their order.
+ */
+ function stealFromOtherARIAOwns()
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, getNode("t3_container2"))
+ ];
+
+ this.invoke = function stealFromOtherARIAOwns_invoke()
+ {
+ getNode("t3_container2").setAttribute("aria-owns", "t3_child");
+ }
+
+ this.finalCheck = function stealFromOtherARIAOwns_finalCheck()
+ {
+ var tree =
+ { SECTION: [
+ ] };
+ testAccessibleTree("t3_container1", tree);
+
+ tree =
+ { SECTION: [
+ { CHECKBUTTON: [
+ ] }
+ ] };
+ testAccessibleTree("t3_container2", tree);
+ }
+
+ this.getID = function stealFromOtherARIAOwns_getID()
+ {
+ return "Steal an element from other ARIA owns element";
+ }
+ }
+
+ function appendElToRecacheChildren()
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, getNode("t3_container2"))
+ ];
+
+ this.invoke = function appendElToRecacheChildren_invoke()
+ {
+ var div = document.createElement("div");
+ div.setAttribute("role", "radio")
+ getNode("t3_container2").appendChild(div);
+ }
+
+ this.finalCheck = function appendElToRecacheChildren_finalCheck()
+ {
+ var tree =
+ { SECTION: [
+ ] };
+ testAccessibleTree("t3_container1", tree);
+
+ tree =
+ { SECTION: [
+ { RADIOBUTTON: [ ] },
+ { CHECKBUTTON: [ ] } // ARIA owned
+ ] };
+ testAccessibleTree("t3_container2", tree);
+ }
+
+ this.getID = function appendElToRecacheChildren_getID()
+ {
+ return "Append a child under @aria-owns element to trigger children recache";
+ }
+ }
+
+ function showHiddenElement()
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, getNode("t4_container1"))
+ ];
+
+ this.invoke = function showHiddenElement_invoke()
+ {
+ var tree =
+ { SECTION: [
+ { RADIOBUTTON: [] }
+ ] };
+ testAccessibleTree("t4_container1", tree);
+
+ getNode("t4_child1").style.display = "block";
+ }
+
+ this.finalCheck = function showHiddenElement_finalCheck()
+ {
+ var tree =
+ { SECTION: [
+ { CHECKBUTTON: [] },
+ { RADIOBUTTON: [] }
+ ] };
+ testAccessibleTree("t4_container1", tree);
+ }
+
+ this.getID = function showHiddenElement_getID()
+ {
+ return "Show hidden ARIA owns referred element";
+ }
+ }
+
+ function rearrangeARIAOwns(aContainer, aAttr, aIdList, aRoleList)
+ {
+ this.eventSeq = [];
+ for (var id of aIdList) {
+ this.eventSeq.push(new invokerChecker(EVENT_HIDE, getNode(id)));
+ }
+
+ for (var id of aIdList) {
+ this.eventSeq.push(new invokerChecker(EVENT_SHOW, getNode(id)));
+ }
+ this.eventSeq.push(new invokerChecker(EVENT_REORDER, getNode(aContainer)));
+
+ this.invoke = function rearrangeARIAOwns_invoke()
+ {
+ getNode(aContainer).setAttribute("aria-owns", aAttr);
+ }
+
+ this.finalCheck = function rearrangeARIAOwns_finalCheck()
+ {
+ var tree = { SECTION: [ ] };
+ for (var role of aRoleList) {
+ var ch = {};
+ ch[role] = [];
+ tree["SECTION"].push(ch);
+ }
+ testAccessibleTree(aContainer, tree);
+ }
+
+ this.getID = function rearrangeARIAOwns_getID()
+ {
+ return `Rearrange @aria-owns attribute to '${aAttr}'`;
+ }
+ }
+
+ function removeNotARIAOwnedEl(aContainer, aChild)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, aContainer)
+ ];
+
+ this.invoke = function removeNotARIAOwnedEl_invoke()
+ {
+ var tree = {
+ SECTION: [
+ { TEXT_LEAF: [ ] },
+ { GROUPING: [ ] }
+ ]
+ };
+ testAccessibleTree(aContainer, tree);
+
+ getNode(aContainer).removeChild(getNode(aChild));
+ }
+
+ this.finalCheck = function removeNotARIAOwnedEl_finalCheck()
+ {
+ var tree = {
+ SECTION: [
+ { GROUPING: [ ] }
+ ]
+ };
+ testAccessibleTree(aContainer, tree);
+ }
+
+ this.getID = function removeNotARIAOwnedEl_getID()
+ {
+ return `remove not ARIA owned child`;
+ }
+ }
+
+ function setARIAOwnsOnElToRemove(aParent, aChild)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getAccessible(aParent))
+ ];
+
+ this.invoke = function setARIAOwnsOnElToRemove_invoke()
+ {
+ getNode(aChild).setAttribute("aria-owns", "no_id");
+ getNode(aParent).removeChild(getNode(aChild));
+ getNode(aParent).parentNode.removeChild(getNode(aParent));
+ }
+
+ this.getID = function setARIAOwnsOnElToRemove_getID()
+ {
+ return `set ARIA owns on an element, and then remove it, and then remove its parent`;
+ }
+ }
+
+ /**
+ * Set ARIA owns on inaccessible span element that contains
+ * accessible children. This will move children from the container for
+ * the span.
+ */
+ function test8()
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, "t8_container")
+ ];
+
+ this.invoke = function test8_invoke()
+ {
+ var tree =
+ { SECTION: [
+ { PUSHBUTTON: [] },
+ { ENTRY: [] },
+ { ENTRY: [] },
+ { ENTRY: [] }
+ ] };
+ testAccessibleTree("t8_container", tree);
+
+ getNode(t8_container).setAttribute("aria-owns", "t8_span t8_button");
+ }
+
+ this.finalCheck = function test8_finalCheck()
+ {
+ var tree =
+ { SECTION: [
+ { TEXT: [
+ { ENTRY: [] },
+ { ENTRY: [] },
+ { ENTRY: [] }
+ ] },
+ { PUSHBUTTON: [] }
+ ] };
+ testAccessibleTree("t8_container", tree);
+ }
+
+ this.getID = function test8_getID()
+ {
+ return `Set ARIA owns on inaccessible span element that contains accessible children`;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Test
+ ////////////////////////////////////////////////////////////////////////////
+
+ //gA11yEventDumpToConsole = true;
+ //enableLogging("tree,eventTree,verbose"); // debug stuff
+
+ var gQueue = null;
+
+ function doTest()
+ {
+ gQueue = new eventQueue();
+
+ // test1
+ gQueue.push(new changeARIAOwns());
+ gQueue.push(new removeARIAOwns());
+ gQueue.push(new setARIAOwns());
+ gQueue.push(new addIdToARIAOwns());
+ gQueue.push(new appendEl());
+ gQueue.push(new removeEl());
+ gQueue.push(new removeId());
+ gQueue.push(new setId());
+
+ // test2
+ gQueue.push(new removeA11eteiner());
+
+ // test3
+ gQueue.push(new stealFromOtherARIAOwns());
+ gQueue.push(new appendElToRecacheChildren());
+
+ // test4
+ gQueue.push(new showHiddenElement());
+
+ // test5
+ gQueue.push(new rearrangeARIAOwns(
+ "t5_container", "t5_checkbox t5_radio t5_button",
+ [ "t5_checkbox", "t5_radio", "t5_button" ],
+ [ "CHECKBUTTON", "RADIOBUTTON", "PUSHBUTTON" ]));
+ gQueue.push(new rearrangeARIAOwns(
+ "t5_container", "t5_radio t5_button t5_checkbox",
+ [ "t5_radio", "t5_button" ],
+ [ "RADIOBUTTON", "PUSHBUTTON", "CHECKBUTTON" ]));
+
+ gQueue.push(new removeNotARIAOwnedEl("t6_container", "t6_span"));
+
+ gQueue.push(new setARIAOwnsOnElToRemove("t7_parent", "t7_child"));
+
+ gQueue.push(new test8());
+
+ gQueue.invoke(); // SimpleTest.finish() will be called in the end
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+
+ </script>
+</head>
+
+<body>
+
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <div id="t1_container" aria-owns="t1_checkbox t1_button">
+ <div role="button" id="t1_button"></div>
+ <div role="checkbox" id="t1_checkbox">
+ <span id="t1_span">
+ <div id="t1_subdiv"></div>
+ </span>
+ </div>
+ </div>
+ <div id="t1_group" role="group"></div>
+ <div id="t1_grouptmp" role="group"></div>
+
+ <div id="t2_container1" aria-owns="t2_owned"></div>
+ <div id="t2_container2">
+ <div id="t2_container3"><div id="t2_owned" role="checkbox"></div></div>
+ </div>
+
+ <div id="t3_container1" aria-owns="t3_child"></div>
+ <div id="t3_child" role="checkbox"></div>
+ <div id="t3_container2"></div>
+
+ <div id="t4_container1" aria-owns="t4_child1 t4_child2"></div>
+ <div id="t4_container2">
+ <div id="t4_child1" style="display:none" role="checkbox"></div>
+ <div id="t4_child2" role="radio"></div>
+ </div>
+
+ <div id="t5_container">
+ <div role="button" id="t5_button"></div>
+ <div role="checkbox" id="t5_checkbox"></div>
+ <div role="radio" id="t5_radio"></div>
+ </div>
+
+ <div id="t6_container" aria-owns="t6_fake">
+ <span id="t6_span">hey</span>
+ </div>
+ <div id="t6_fake" role="group"></div>
+
+ <div id="t7_container">
+ <div id="t7_parent">
+ <div id="t7_child"></div>
+ </div>
+ </div>
+
+ <div id="t8_container">
+ <input id="t8_button" type="button"><span id="t8_span"><input><input><input></span>
+ </div>
+</body>
+
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_bug1040735.html b/accessible/tests/mochitest/treeupdate/test_bug1040735.html
new file mode 100644
index 000000000..527f23197
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_bug1040735.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Adopt DOM node from anonymous subtree</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">
+ function doTest()
+ {
+ document.body.appendChild(document.getElementById("mw_a"));
+ setTimeout(function() { ok(true, "no crash and assertions"); SimpleTest.finish(); } , 0);
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+</head>
+
+<body>
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=1040735"
+ title="Bug 1040735 - DOM node reinsertion under anonymous content may trigger a11y child adoption">
+ Bug 1040735</a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <marquee>
+ <div id="mw_a" style="visibility: hidden;">
+ <div style="visibility: visible;" id="mw_inside"></div>
+ </div>
+ </marquee>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_bug1100602.html b/accessible/tests/mochitest/treeupdate/test_bug1100602.html
new file mode 100644
index 000000000..1637e5057
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_bug1100602.html
@@ -0,0 +1,114 @@
+<html>
+
+<head>
+ <title>Test hide/show events for HTMLListBulletAccessibles on list restyle</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="../name.js"></script>
+ <script type="application/javascript"
+ src="../events.js"></script>
+
+ <script type="application/javascript">
+ /**
+ * Change list style type to none.
+ */
+ function hideBullet()
+ {
+ this.eventSeq = [];
+ this.liAcc = getAccessible("list_element");
+ this.bullet = this.liAcc.firstChild;
+
+ this.eventSeq.push(new invokerChecker(EVENT_HIDE, this.bullet));
+ this.eventSeq.push(new invokerChecker(EVENT_REORDER, this.liAcc));
+
+ this.invoke = function hideBullet_invoke()
+ {
+ getNode("list").setAttribute("style", "list-style-type: none;");
+ }
+
+ this.finalCheck = function hideBullet_finalCheck()
+ {
+ is(this.liAcc.name, "list element",
+ "Check that first child of LI is not a bullet.");
+ }
+
+ this.getID = function hideBullet_getID()
+ {
+ return "Hide bullet by setting style to none";
+ }
+ }
+
+ /**
+ * Change list style type to circles.
+ */
+ function showBullet()
+ {
+ this.eventSeq = [];
+ this.liAcc = getAccessible("list_element");
+
+ this.eventSeq.push(new invokerChecker(EVENT_SHOW,
+ function(aNode) { return aNode.firstChild; },
+ this.liAcc));
+ this.eventSeq.push(new invokerChecker(EVENT_REORDER, this.liAcc));
+
+ this.invoke = function showBullet_invoke()
+ {
+ getNode("list").setAttribute("style", "list-style-type: circle;");
+ }
+
+ this.finalCheck = function showBullet_finalCheck()
+ {
+ is(this.liAcc.name, "â—¦ list element",
+ "Check that first child of LI is a circle bullet.");
+ }
+
+ this.getID = function showBullet_getID()
+ {
+ return "Show bullet by setting style to circle";
+ }
+ }
+
+ var gQueue = null;
+ function doTest()
+ {
+
+ var list = getNode("list");
+ list.setAttribute("style", "list-style-type: circle;");
+
+ gQueue = new eventQueue();
+ gQueue.push(new hideBullet());
+ gQueue.push(new showBullet());
+ gQueue.invoke(); // SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+
+</head>
+
+<body>
+
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=1100602"
+ title="[e10s] crash in mozilla::a11y::ProxyAccessible::Shutdown()">
+ Mozilla Bug 1100602
+ </a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <ol id="list">
+ <li id="list_element">list element</li>
+ </ol>
+
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_bug1175913.html b/accessible/tests/mochitest/treeupdate/test_bug1175913.html
new file mode 100644
index 000000000..5dab9b5a8
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_bug1175913.html
@@ -0,0 +1,105 @@
+<html>
+
+<head>
+ <title>Test hide/show events on event listener changes</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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ function dummyListener() {}
+
+ function testAddListener()
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_SHOW, getNode("parent")),
+ ];
+
+ this.invoke = function testAddListener_invoke()
+ {
+ is(getAccessible("parent", null, null, DONOTFAIL_IF_NO_ACC), null, "Check that parent is not accessible.");
+ is(getAccessible("child", null, null, DONOTFAIL_IF_NO_ACC), null, "Check that child is not accessible.");
+ getNode("parent").addEventListener("click", dummyListener);
+ }
+
+ this.finalCheck = function testAddListener_finalCheck()
+ {
+ var tree = { TEXT: [] };
+ testAccessibleTree("parent", tree);
+ }
+
+ this.getID = function testAddListener_getID()
+ {
+ return "Test that show event is sent when click listener is added";
+ }
+ }
+
+ function testRemoveListener()
+ {
+ this.eventSeq = [
+ new unexpectedInvokerChecker(EVENT_HIDE, getNode("parent")),
+ ];
+
+ this.invoke = function testRemoveListener_invoke()
+ {
+ getNode("parent").removeEventListener("click", dummyListener);
+ }
+
+ this.finalCheck = function testRemoveListener_finalCheck()
+ {
+ ok(getAccessible("parent", null, null, DONOTFAIL_IF_NO_ACC),
+ "Parent stays accessible after click event listener is removed");
+ ok(!getAccessible("child", null, null, DONOTFAIL_IF_NO_ACC),
+ "Child stays inaccessible");
+ }
+
+ this.getID = function testRemoveListener_getID()
+ {
+ return "Test that hide event is sent when click listener is removed";
+ }
+ }
+
+ var gQueue = null;
+ function doTest()
+ {
+ gQueue = new eventQueue();
+ gQueue.push(new testAddListener());
+ gQueue.push(new testRemoveListener());
+ gQueue.invoke(); // SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+
+</head>
+
+<body>
+
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=1175913"
+ title="Crash in mozilla::a11y::DocAccessibleParent::RemoveAccessible(ProxyAccessible* aAccessible)">
+ Mozilla Bug 1175913
+ </a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <span id="parent">
+ <span id="child">
+ </span>
+ </span>
+
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_bug1189277.html b/accessible/tests/mochitest/treeupdate/test_bug1189277.html
new file mode 100644
index 000000000..9c995d49e
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_bug1189277.html
@@ -0,0 +1,86 @@
+<html>
+
+<head>
+ <title>Test hide/show events for HTMLListBulletAccessibles on list restyle</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="../name.js"></script>
+ <script type="application/javascript"
+ src="../events.js"></script>
+
+ <script type="application/javascript">
+ function runTest()
+ {
+ this.containerNode = getNode("outerDiv");
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getNode("child")),
+ new invokerChecker(EVENT_HIDE, getNode("childDoc")),
+ new invokerChecker(EVENT_SHOW, "newChildDoc"),
+ new invokerChecker(EVENT_REORDER, this.containerNode)
+ ];
+
+ this.invoke = function runTest_invoke()
+ {
+ this.containerNode.removeChild(getNode("child"));
+
+ var docContainer = getNode("docContainer");
+ var iframe = document.createElement("iframe");
+ iframe.setAttribute("src", "http://example.com");
+ iframe.setAttribute("id", "newChildDoc");
+
+ docContainer.removeChild(getNode("childDoc"));
+ docContainer.appendChild(iframe);
+ }
+
+ this.getID = function runTest_getID()
+ {
+ return "check show events are not incorrectly coalesced";
+ }
+ }
+
+ //enableLogging("tree");
+ gA11yEventDumpToConsole = true;
+ var gQueue = null;
+ function doTest()
+ {
+ gQueue = new eventQueue();
+ gQueue.push(new runTest());
+ gQueue.invoke(); // SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+
+</head>
+
+<body>
+
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=1189277"
+ title="content process crash caused by missing show event">
+ Mozilla Bug 1189277
+ </a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <div id="outerDiv">
+ <div id="child">foo</div>
+ <div id="docContainer">
+ <iframe id="childDoc" src="about:blank">
+ </iframe>
+ </div>
+ </div>
+
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_bug1276857.html b/accessible/tests/mochitest/treeupdate/test_bug1276857.html
new file mode 100644
index 000000000..5eceae9eb
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_bug1276857.html
@@ -0,0 +1,143 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>DOM mutations test</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="../events.js"></script>
+
+ <script type="application/javascript">
+ function runTest()
+ {
+ // children change will recreate the table
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, getNode('c1'))
+ ];
+
+ this.invoke = function runTest_invoke() {
+ var tree = {
+ SECTION: [ // c1
+ { TEXT_LEAF: [] }, // Some text
+ { TEXT_CONTAINER: [
+ { TEXT_LEAF: [] } // something with ..
+ ] },
+ { TEXT_LEAF: [] } // More text
+ ]
+ };
+ testAccessibleTree('c1', tree);
+
+ getNode('c1_t').querySelector('span').remove();
+ };
+
+ this.finalCheck = function runTest_finalCheck() {
+ var tree = {
+ SECTION: [ // c1
+ { TEXT_LEAF: [] }, // Some text
+ { TEXT_LEAF: [] } // More text
+ ]
+ };
+ testAccessibleTree('c1', tree);
+ };
+
+ this.getID = function runTest_getID()
+ {
+ return 'child DOM node is removed before the layout notifies the a11y about parent removal/show';
+ };
+ }
+
+ function runShadowTest()
+ {
+ // children change will recreate the table
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, 'c2')
+ ];
+
+ this.invoke = function runShadowTest_invoke() {
+ var tree = {
+ SECTION: [ // c2
+ { TEXT_LEAF: [] }, // Some text
+ { TEXT_CONTAINER: [
+ { TEXT_LEAF: [] } // something with ..
+ ] },
+ { TEXT_LEAF: [] } // More text
+ ]
+ };
+ testAccessibleTree('c2', tree);
+
+ gShadowRoot.firstElementChild.querySelector('span').remove();
+ };
+
+ this.finalCheck = function runShadowTest_finalCheck() {
+ var tree = {
+ SECTION: [ // c2
+ { TEXT_LEAF: [] }, // Some text
+ { TEXT_LEAF: [] } // More text
+ ]
+ };
+ testAccessibleTree('c2', tree);
+ };
+
+ this.getID = function runShadowTest_getID() {
+ return 'child DOM node is removed before the layout notifies the a11y about parent removal/show in shadow DOM';
+ };
+ }
+
+ //enableLogging("tree");
+ //gA11yEventDumpToConsole = true;
+
+ var gQueue = null;
+ function doTest()
+ {
+ gQueue = new eventQueue();
+ gQueue.push(new runTest());
+ gQueue.push(new runShadowTest());
+ gQueue.invoke(); // will call SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+
+</head>
+
+<body>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <div id="c1">
+ <div id="c1_t" style="display: table" role="presentation">
+ Some text
+ <span style="display: table-cell">something with accessibles goes here</span>
+ More text
+ </div>
+ </div>
+
+ <template id="tmpl">
+ <div style="display: table" role="presentation">
+ Some text
+ <span style="display: table-cell">something with accessibles goes here</span>
+ More text
+ </div>
+ </template>
+
+ <div id="c2"><div id="c2_c" role="presentation"></div></div>
+
+ <script>
+ var gShadowRoot = document.getElementById('c2_c').createShadowRoot();
+ var tmpl = document.getElementById('tmpl');
+ gShadowRoot.appendChild(document.importNode(tmpl.content, true));
+ </script>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_bug852150.xhtml b/accessible/tests/mochitest/treeupdate/test_bug852150.xhtml
new file mode 100644
index 000000000..094d148a0
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_bug852150.xhtml
@@ -0,0 +1,59 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Canvas subdom mutation</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>
+ <![CDATA[
+ function doTest()
+ {
+ var the_displayNone = getNode("the_displaynone");
+ var the_table = getNode("the_table");
+ var the_row = getNode("the_row");
+ ok(isAccessible(the_table), "table should be accessible");
+ the_displayNone.appendChild(the_table);
+ ok(!isAccessible(the_table), "table in display none tree shouldn't be accessible");
+
+ setTimeout(function() {
+ document.body.removeChild(the_row);
+ // make sure no accessibles have stuck around.
+ ok(!isAccessible(the_row), "row shouldn't be accessible");
+ ok(!isAccessible(the_table), "table shouldn't be accessible");
+ ok(!isAccessible(the_displayNone), "display none things shouldn't be accessible");
+ SimpleTest.finish();
+ }, 0);
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ ]]>
+ </script>
+</head>
+<body>
+
+ <a target="_blank"
+ title="test accessible removal when reframe root isn't accessible"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=852150">
+ Mozilla Bug 852150
+ </a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <div id="the_displaynone" style="display: none;"></div>
+ <table id="the_table"></table>
+ <tr id="the_row"></tr>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_bug883708.xhtml b/accessible/tests/mochitest/treeupdate/test_bug883708.xhtml
new file mode 100644
index 000000000..6265a1c7f
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_bug883708.xhtml
@@ -0,0 +1,33 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script>
+
+function boom()
+{
+ var newSpan = document.createElementNS("http://www.w3.org/1999/xhtml", "span");
+ c.insertBefore(newSpan, d);
+ a.style.visibility = "visible";
+ ok(true, "test didn't crash or assert");
+ SimpleTest.finish();
+}
+
+</script>
+</head>
+
+<body onload="boom();">
+ <a target="_blank"
+ title="test reparenting accessible subtree when inaccessible element becomes accessible"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=883708">
+ Mozilla Bug 883708
+ </a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+<div style="visibility: collapse;" id="a"><div style="float: right; visibility: visible;"><div id="c"><td id="d"></td></div></div></div></body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_bug884251.xhtml b/accessible/tests/mochitest/treeupdate/test_bug884251.xhtml
new file mode 100644
index 000000000..d1821188b
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_bug884251.xhtml
@@ -0,0 +1,21 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script>
+
+function boom()
+{
+ document.getElementById("k").removeAttribute("href");
+ ok(true, "changing iframe contents doesn't cause assertions");
+ SimpleTest.finish();
+}
+
+</script>
+</head>
+
+<body onload="boom();">
+<iframe src="data:text/html,1"><link id="k" href="data:text/html,2" /></iframe>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_bug895082.html b/accessible/tests/mochitest/treeupdate/test_bug895082.html
new file mode 100644
index 000000000..aaefdc46c
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_bug895082.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Replace body test</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="../events.js"></script>
+
+ <script type="application/javascript">
+function doTest()
+{
+ var y = document.getElementById("y");
+ var oldBody = document.body;
+ var newBody = document.createElement("body")
+ document.documentElement.insertBefore(newBody, oldBody);
+ setTimeout(function() {
+ document.documentElement.removeChild(oldBody);
+ newBody.appendChild(y);
+ ok(true, "we didn't assert");
+ SimpleTest.finish();
+ }, 0);
+}
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=895082"
+ title="Bug 895082 - replacing body element asserts">
+ Bug 895082</a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+<div><div id="y"></div></div>
+
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_canvas.html b/accessible/tests/mochitest/treeupdate/test_canvas.html
new file mode 100644
index 000000000..6ae129a67
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_canvas.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Canvas subdom mutation</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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Invokers
+
+ function addSubtree(aID)
+ {
+ this.node = getNode(aID);
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_SHOW, this.node)
+ ];
+
+ this.invoke = function addSubtree_invoke()
+ {
+ // ensure we start with no subtree
+ testAccessibleTree("canvas", { CANVAS: [] });
+ getNode("dialog").style.display = "block";
+ }
+
+ this.finalCheck = function addSubtree_finalCheck() {
+ testAccessibleTree("dialog", { DIALOG: [] });
+ }
+
+ this.getID = function addSubtree_getID()
+ {
+ return "show canvas subdom";
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Test
+
+ //gA11yEventDumpID = "eventdump"; // debug stuff
+ //gA11yEventDumpToConsole = true;
+
+ var gQueue = null;
+
+ function doTest()
+ {
+ gQueue = new eventQueue();
+
+ // make the subdom come alive!
+ gQueue.push(new addSubtree("dialog"));
+
+ gQueue.invoke(); // SimpleTest.finish() will be called in the end
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank"
+ title="Expose content in Canvas element"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=495912">
+ Mozilla Bug 495912
+ </a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <canvas id="canvas">
+ <div id="dialog" role="dialog" style="display: none;">
+ </div>
+ </canvas>
+
+ <div id="eventdump"></div>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_colorpicker.xul b/accessible/tests/mochitest/treeupdate/test_colorpicker.xul
new file mode 100644
index 000000000..9b15c9174
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_colorpicker.xul
@@ -0,0 +1,150 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="Accessible XUL button hierarchy tests">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+
+ <script type="application/javascript"
+ src="../common.js" />
+ <script type="application/javascript"
+ src="../role.js" />
+ <script type="application/javascript"
+ src="../events.js" />
+
+ <script type="application/javascript">
+ <![CDATA[
+ ////////////////////////////////////////////////////////////////////////////
+ // Test
+
+ function openColorpicker(aColorpickerID)
+ {
+ this.node = getNode(aColorpickerID);
+
+ this.eventSeq = [];
+
+ var it = new colorButtonIterator(this.node);
+ for (var btnNode = it.next(); btnNode = it.next(); btnNode)
+ this.eventSeq.push(new invokerChecker(EVENT_SHOW, btnNode));
+
+ var popupNode = getPopupNode(this.node);
+ this.eventSeq.push(new invokerChecker(EVENT_REORDER, popupNode));
+
+ this.invoke = function openColorpicker_invoke()
+ {
+ var tree =
+ { BUTTONDROPDOWNGRID: [
+ { ALERT: [ ] }
+ ] };
+ testAccessibleTree(this.node, tree);
+
+ this.node.showPopup();
+ }
+
+ this.finalCheck = function openColorpicker_finalCheck()
+ {
+ var tree =
+ { BUTTONDROPDOWNGRID: [
+ { ALERT: [ ] }
+ ] };
+
+ var colorButtons = tree.BUTTONDROPDOWNGRID[0].ALERT;
+ var it = new colorButtonIterator(this.node);
+ while (it.next()) {
+ var obj = { PUSHBUTTON: [ ] };
+ colorButtons.push(obj);
+ }
+
+ testAccessibleTree(this.node, tree);
+ }
+
+ this.getID = function openColorpicker_getID()
+ {
+ return "open colorpicker " + prettyName(aColorpickerID);
+ }
+ }
+
+ function getPopupNode(aColorpickerNode)
+ {
+ return aColorpickerNode.mPicker.parentNode;
+ }
+
+ function colorButtonIterator(aColorpickerNode)
+ {
+ this.container = aColorpickerNode.mPicker.mBox;
+ this.group = this.container.firstChild;
+ this.item = null;
+
+ this.next = function colorButtonIterator_next()
+ {
+ if (!this.group)
+ return null;
+
+ if (!this.item) {
+ this.item = this.group.firstChild;
+ return this.item;
+ }
+
+ if (this.item.nextSibling) {
+ this.item = this.item.nextSibling;
+ return this.item;
+ }
+
+ if (this.group.nextSibling) {
+ this.group = this.group.nextSibling;
+ this.item = this.group.firstChild;
+ return this.item;
+ }
+
+ this.group = null;
+ this.item = null;
+ return null;
+ }
+ }
+
+ //gA11yEventDumpToConsole = true; // debug stuff
+
+ var gQueue = null;
+ function doTest()
+ {
+ gQueue = new eventQueue();
+ gQueue.push(new openColorpicker("colorpicker"));
+ gQueue.invoke(); // Will call SimpleTest.finish()
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ ]]>
+ </script>
+
+ <hbox flex="1" style="overflow: auto;">
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=249292"
+ title="Ensure accessible children for toolbarbutton types 'menu' and 'menu-button'">
+ Mozilla Bug 249292
+ </a>
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=630486"
+ title="Don't force accessible creation for popup children.">
+ Mozilla Bug 630486
+ </a>
+ <br/>
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <vbox flex="1">
+ <colorpicker id="colorpicker" type="button"/>
+ </vbox>
+ </hbox>
+
+</window>
+
diff --git a/accessible/tests/mochitest/treeupdate/test_contextmenu.xul b/accessible/tests/mochitest/treeupdate/test_contextmenu.xul
new file mode 100644
index 000000000..5b31e0136
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_contextmenu.xul
@@ -0,0 +1,317 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="menu tree and events">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
+
+ <script type="application/javascript"
+ src="../common.js" />
+ <script type="application/javascript"
+ src="../events.js" />
+ <script type="application/javascript"
+ src="../role.js" />
+
+ <script type="application/javascript">
+ <![CDATA[
+
+ function openMenu(aID, aTree)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_MENUPOPUP_START, getNode(aID))
+ ];
+
+ this.invoke = function openMenu_invoke()
+ {
+ var button = getNode("button");
+ getNode(aID).openPopup(button, "after_start", 0, 0, true, false);
+ }
+
+ this.finalCheck = function openMenu_finalCheck(aEvent)
+ {
+ testAccessibleTree(aID, aTree);
+ }
+
+ this.getID = function openMenu_getID()
+ {
+ return "open menu " + prettyName(aID);
+ }
+ }
+
+ function selectNextMenuItem(aID)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_FOCUS, getNode(aID))
+ ];
+
+ this.invoke = function selectMenuItem_invoke()
+ {
+ synthesizeKey("VK_DOWN", { });
+ }
+
+ this.getID = function selectMenuItem_getID()
+ {
+ return "select menuitem " + prettyName(aID);
+ }
+ }
+
+ function openSubMenu(aSubMenuID, aItemID, aMenuID, aTree)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_FOCUS, getNode(aItemID)),
+ ];
+
+ this.invoke = function openSubMenu_invoke()
+ {
+ synthesizeKey("VK_RETURN", { });
+ }
+
+ this.finalCheck = function openSubMenu_finalCheck(aEvent)
+ {
+ testAccessibleTree(aMenuID, aTree);
+ }
+
+ this.getID = function openSubMenu_getID()
+ {
+ return "open submenu " + prettyName(aSubMenuID) + " focusing item " + prettyName(aItemID);
+ }
+ }
+
+ function closeSubMenu(aSubMenuID, aItemID)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_FOCUS, getNode(aItemID)),
+ ];
+
+ this.invoke = function closeSubMenu_invoke()
+ {
+ synthesizeKey("VK_ESCAPE", { });
+ }
+
+ this.getID = function closeSubMenu_getID()
+ {
+ return "close submenu " + prettyName(aSubMenuID) + " focusing item " + prettyName(aItemID);
+ }
+ }
+
+ function closeMenu(aID)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_MENUPOPUP_END, getNode(aID))
+ ];
+
+ this.invoke = function closeMenu_invoke()
+ {
+ synthesizeKey("VK_ESCAPE", { });
+ }
+
+ this.getID = function closeMenu_getID()
+ {
+ return "close menu " + prettyName(aID);
+ }
+ }
+
+ //gA11yEventDumpToConsole = true;
+ //enableLogging("tree,verbose");
+
+ var gQueue = null;
+ var gContextTree = {};
+
+ // Linux and Windows menu trees discrepancy: bug 527646.
+
+ /**
+ * Return the context menu tree before submenus were open.
+ */
+ function getMenuTree1()
+ {
+ if (LINUX || SOLARIS) {
+ var tree = {
+ role: ROLE_MENUPOPUP,
+ children: [
+ {
+ name: "item0",
+ role: ROLE_MENUITEM,
+ children: []
+ },
+ {
+ name: "item1",
+ role: ROLE_MENUITEM,
+ children: []
+ },
+ {
+ name: "item2",
+ role: ROLE_PARENT_MENUITEM,
+ children: [ ]
+ }
+ ]
+ };
+ return tree;
+ }
+
+ // Windows
+ var tree = {
+ role: ROLE_MENUPOPUP,
+ children: [
+ {
+ name: "item0",
+ role: ROLE_MENUITEM,
+ children: []
+ },
+ {
+ name: "item1",
+ role: ROLE_MENUITEM,
+ children: []
+ },
+ {
+ name: "item2",
+ role: ROLE_PARENT_MENUITEM,
+ children: [
+ {
+ name: "item2",
+ role: ROLE_MENUPOPUP,
+ children: [ ]
+ }
+ ]
+ }
+ ]
+ };
+ return tree;
+ }
+
+ /**
+ * Return context menu tree when submenu was open.
+ */
+ function getMenuTree2()
+ {
+ var tree = getMenuTree1();
+ if (LINUX || SOLARIS) {
+ var submenuTree =
+ {
+ name: "item2.0",
+ role: ROLE_PARENT_MENUITEM,
+ children: [ ]
+ };
+ tree.children[2].children.push(submenuTree);
+ return tree;
+ }
+
+ // Windows
+ var submenuTree =
+ {
+ name: "item2.0",
+ role: ROLE_PARENT_MENUITEM,
+ children: [
+ {
+ name: "item2.0",
+ role: ROLE_MENUPOPUP,
+ children: [ ]
+ }
+ ]
+ };
+
+ tree.children[2].children[0].children.push(submenuTree);
+ return tree;
+ }
+
+ /**
+ * Return context menu tree when subsub menu was open.
+ */
+ function getMenuTree3()
+ {
+ var tree = getMenuTree2();
+ var subsubmenuTree =
+ {
+ name: "item2.0.0",
+ role: ROLE_MENUITEM,
+ children: []
+ };
+
+ if (LINUX || SOLARIS)
+ tree.children[2].children[0].children.push(subsubmenuTree);
+ else
+ tree.children[2].children[0].children[0].children[0].children.push(subsubmenuTree);
+
+ return tree;
+ }
+
+
+ function doTests()
+ {
+ gQueue = new eventQueue();
+
+ // Check initial empty tree
+ testAccessibleTree("context", { MENUPOPUP: [] });
+
+ // Open context menu and check that menu item accesibles are created.
+ gQueue.push(new openMenu("context", getMenuTree1()));
+
+ // Select items and check focus event on them.
+ gQueue.push(new selectNextMenuItem("item0"));
+ gQueue.push(new selectNextMenuItem("item1"));
+ gQueue.push(new selectNextMenuItem("item2"));
+
+ // Open sub menu and check menu accessible tree and focus event.
+ gQueue.push(new openSubMenu("submenu2", "item2.0",
+ "context", getMenuTree2()));
+ gQueue.push(new openSubMenu("submenu2.0", "item2.0.0",
+ "context", getMenuTree3()));
+
+ // Close submenus and check that focus goes to parent.
+ gQueue.push(new closeSubMenu("submenu2.0", "item2.0"));
+ gQueue.push(new closeSubMenu("submenu2", "item2"));
+
+ gQueue.push(new closeMenu("context"));
+
+ gQueue.invoke(); // Will call SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTests);
+ ]]>
+ </script>
+
+ <hbox flex="1" style="overflow: auto;">
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=630194"
+ title="Update accessible tree when opening the menu popup">
+ Mozilla Bug 630194
+ </a>
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=630486"
+ title="Don't force accessible creation for popup children.">
+ Mozilla Bug 630486
+ </a>
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <vbox flex="1">
+
+ <menupopup id="context">
+ <menuitem id="item0" label="item0"/>
+ <menuitem id="item1" label="item1"/>
+ <menu id="item2" label="item2">
+ <menupopup id="submenu2">
+ <menu id="item2.0" label="item2.0">
+ <menupopup id="submenu2.0">
+ <menuitem id="item2.0.0" label="item2.0.0"/>
+ </menupopup>
+ </menu>
+ </menupopup>
+ </menu>
+ </menupopup>
+
+ <button context="context" id="button">btn</button>
+ </vbox>
+ </hbox>
+</window>
diff --git a/accessible/tests/mochitest/treeupdate/test_cssoverflow.html b/accessible/tests/mochitest/treeupdate/test_cssoverflow.html
new file mode 100644
index 000000000..ed9edd66e
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_cssoverflow.html
@@ -0,0 +1,143 @@
+<html>
+
+<head>
+ <title>Testing HTML scrollable frames (css overflow style)</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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Invokers
+ ////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Change scroll range to not empty size and inserts a child into container
+ * to trigger tree update of the container. Prior to bug 677154 not empty
+ * size resulted to accessible creation for scroll area, container tree
+ * update picked up that accessible unattaching scroll area accessible
+ * subtree.
+ */
+ function changeScrollRange(aContainerID, aScrollAreaID)
+ {
+ this.containerNode = getNode(aContainerID);
+ this.container = getAccessible(this.containerNode);
+ this.scrollAreaNode = getNode(aScrollAreaID);
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, this.container)
+ ];
+
+ this.invoke = function changeScrollRange_invoke()
+ {
+ this.scrollAreaNode.style.width = "20px";
+ this.containerNode.appendChild(document.createElement("input"));
+ }
+
+ this.finalCheck = function changeScrollRange_finalCheck()
+ {
+ var accTree =
+ { SECTION: [ // container
+ { SECTION: [ // scroll area
+ { ENTRY: [] } // child content
+ ] },
+ { ENTRY: [] } // inserted input
+ ] };
+ testAccessibleTree(this.container, accTree);
+ }
+
+ this.getID = function changeScrollRange_getID()
+ {
+ return "change scroll range for " + prettyName(aScrollAreaID);
+ }
+ }
+
+ /**
+ * Change scrollbar styles from hidden to auto. That makes us to create an
+ * accessible for scroll area.
+ */
+ function changeScrollbarStyles(aContainerID, aScrollAreaID)
+ {
+ this.container = getAccessible(aContainerID);
+ this.scrollAreaNode = getNode(aScrollAreaID);
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_SHOW, getAccessible, this.scrollAreaNode),
+ new invokerChecker(EVENT_REORDER, this.container)
+ ];
+
+ this.invoke = function changeScrollbarStyles_invoke()
+ {
+ var accTree =
+ { SECTION: [] };
+ testAccessibleTree(this.container, accTree);
+
+ this.scrollAreaNode.style.overflow = "auto";
+ }
+
+ this.finalCheck = function changeScrollbarStyles_finalCheck()
+ {
+ var accTree =
+ { SECTION: [ // container
+ { SECTION: [] } // scroll area
+ ] };
+ testAccessibleTree(this.container, accTree);
+ }
+
+ this.getID = function changeScrollbarStyles_getID()
+ {
+ return "change scrollbar styles " + prettyName(aScrollAreaID);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Do tests
+ ////////////////////////////////////////////////////////////////////////////
+
+ var gQueue = null;
+ //gA11yEventDumpID = "eventdump"; // debug stuff
+ //gA11yEventDumpToConsole = true;
+
+ function doTests()
+ {
+ gQueue = new eventQueue();
+
+ gQueue.push(new changeScrollRange("container", "scrollarea"));
+ gQueue.push(new changeScrollbarStyles("container2", "scrollarea2"));
+
+ gQueue.invoke(); // Will call SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTests);
+ </script>
+</head>
+
+<body>
+
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=677154"
+ title="Detached document accessibility tree">
+ Mozilla Bug 677154</a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+ <div id="eventdump"></div>
+
+ <div id="container"><div id="scrollarea" style="overflow:auto;"><input></div></div>
+ <div id="container2"><div id="scrollarea2" style="overflow:hidden;"></div></div>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_deck.xul b/accessible/tests/mochitest/treeupdate/test_deck.xul
new file mode 100644
index 000000000..13561abab
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_deck.xul
@@ -0,0 +1,109 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="Tree update on XUL deck panel switching">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+
+ <script type="application/javascript"
+ src="../common.js" />
+ <script type="application/javascript"
+ src="../role.js" />
+ <script type="application/javascript"
+ src="../states.js" />
+ <script type="application/javascript"
+ src="../events.js" />
+
+ <script type="application/javascript">
+ <![CDATA[
+ function switchDeckPanel(aContainerID, aDeckID)
+ {
+ this.panelIndex = 0;
+
+ this.container = getAccessible(aContainerID);
+ this.deckNode = getNode(aDeckID);
+ this.prevPanel = getAccessible(this.deckNode.selectedPanel);
+ this.panelNode = this.deckNode.childNodes[this.panelIndex];
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, this.prevPanel),
+ new invokerChecker(EVENT_SHOW, this.panelNode),
+ new invokerChecker(EVENT_REORDER, this.container)
+ ];
+
+ this.invoke = function switchDeckPanel_invoke()
+ {
+ var tree =
+ { GROUPING: [ // role="group"
+ { GROUPING: [ // groupbox, a selected panel #2
+ { PUSHBUTTON: [ ] } // button
+ ] }
+ ] };
+ testAccessibleTree(this.container, tree);
+
+ this.deckNode.selectedIndex = this.panelIndex;
+ }
+
+ this.finalCheck = function switchDeckPanel_finalCheck()
+ {
+ var tree =
+ { GROUPING: [ // role="group"
+ { LABEL: [ // description, a selected panel #1
+ { TEXT_LEAF: [] } // text leaf, a description value
+ ] }
+ ] };
+ testAccessibleTree(this.container, tree);
+ }
+
+ this.getID = function switchDeckPanel_getID()
+ {
+ return "switch deck panel";
+ }
+ }
+
+ var gQueue = null;
+ function doTest()
+ {
+ gQueue = new eventQueue();
+ gQueue.push(new switchDeckPanel("container", "deck"));
+ gQueue.invoke(); // will call SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ ]]>
+ </script>
+
+ <hbox flex="1" style="overflow: auto;">
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=814836"
+ title=" xul:deck element messes up screen reader">
+ Mozilla Bug 814836
+ </a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <vbox flex="1" id="container" role="group">
+
+ <deck id="deck" selectedIndex="1">
+ <description>This is the first page</description>
+ <groupbox>
+ <button label="This is the second page"/>
+ </groupbox>
+ </deck>
+
+ </vbox>
+ </hbox>
+
+</window>
+
diff --git a/accessible/tests/mochitest/treeupdate/test_doc.html b/accessible/tests/mochitest/treeupdate/test_doc.html
new file mode 100644
index 000000000..05896e7b4
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_doc.html
@@ -0,0 +1,466 @@
+<!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>
diff --git a/accessible/tests/mochitest/treeupdate/test_gencontent.html b/accessible/tests/mochitest/treeupdate/test_gencontent.html
new file mode 100644
index 000000000..1cf22b36f
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_gencontent.html
@@ -0,0 +1,160 @@
+<html>
+
+<head>
+ <title>Elements with CSS generated content</title>
+
+ <link rel="stylesheet" type="text/css"
+ href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+ <style>
+ .gentext:before {
+ content: "START"
+ }
+ .gentext:after {
+ content: "END"
+ }
+ </style>
+
+ <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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Invokers
+ ////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Insert new node with CSS generated content style applied to container.
+ */
+ function insertNodeHavingGenContent(aContainerID)
+ {
+ this.containerNode = getNode(aContainerID);
+ this.container = getAccessible(this.containerNode);
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_SHOW, getFirstChild, this.container),
+ new invokerChecker(EVENT_REORDER, this.container)
+ ];
+
+ this.invoke = function insertNodeHavingGenContent_invoke()
+ {
+ var node = document.createElement("div");
+ node.textContent = "text";
+ node.setAttribute("class", "gentext");
+ this.containerNode.appendChild(node);
+ }
+
+ this.finalCheck = function insertNodeHavingGenContent_finalCheck()
+ {
+ var accTree =
+ { SECTION: [ // container
+ { SECTION: [ // inserted node
+ { STATICTEXT: [] }, // :before
+ { TEXT_LEAF: [] }, // primary text
+ { STATICTEXT: [] } // :after
+ ] }
+ ] };
+ testAccessibleTree(this.container, accTree);
+ }
+
+ this.getID = function insertNodeHavingGenContent_getID()
+ {
+ return "insert node having generated content to " + prettyName(aContainerID);
+ }
+ }
+
+ /**
+ * Add CSS generated content to the given node contained by container node.
+ */
+ function addGenContent(aContainerID, aNodeID)
+ {
+ this.container = getAccessible(aContainerID);
+ this.node = getNode(aNodeID);
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, this.container.firstChild),
+ new invokerChecker(EVENT_SHOW, getFirstChild, this.container),
+ new invokerChecker(EVENT_REORDER, this.container)
+ ];
+
+ this.invoke = function addGenContent_invoke()
+ {
+ this.node.setAttribute("class", "gentext");
+ }
+
+ this.finalCheck = function insertNodeHavingGenContent_finalCheck()
+ {
+ var accTree =
+ { SECTION: [ // container
+ { SECTION: [ // inserted node
+ { STATICTEXT: [] }, // :before
+ { TEXT_LEAF: [] }, // primary text
+ { STATICTEXT: [] } // :after
+ ] }
+ ] };
+ testAccessibleTree(this.container, accTree);
+ }
+
+ this.getID = function addGenContent_getID()
+ {
+ return "add generated content to" + prettyName(aNodeID);
+ }
+ }
+
+ /**
+ * Target getters.
+ */
+ function getFirstChild(aAcc)
+ {
+ try { return aAcc.getChildAt(0); }
+ catch (e) { return null; }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Do tests
+ ////////////////////////////////////////////////////////////////////////////
+
+ var gQueue = null;
+ //gA11yEventDumpID = "eventdump"; // debug stuff
+ //gA11yEventDumpToConsole = true;
+
+ function doTests()
+ {
+ gQueue = new eventQueue();
+
+ gQueue.push(new insertNodeHavingGenContent("container1"));
+ gQueue.push(new addGenContent("container2", "container2_child"));
+
+ gQueue.invoke(); // Will call SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTests);
+ </script>
+</head>
+
+<body>
+
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=646350"
+ title="Add a test for dynamic chnages of CSS generated content">
+ Mozilla Bug 646350</a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+ <div id="eventdump"></div>
+
+ <div id="container1"></div>
+ <div id="container2"><div id="container2_child">text</div></div>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_general.html b/accessible/tests/mochitest/treeupdate/test_general.html
new file mode 100644
index 000000000..9a8862bea
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_general.html
@@ -0,0 +1,150 @@
+<html>
+
+<head>
+ <title>Testing the tree updates</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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Invokers
+ ////////////////////////////////////////////////////////////////////////////
+
+ function prependAppend(aContainer)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, aContainer)
+ ];
+
+ this.invoke = function prependAppend_invoke()
+ {
+ var checkbox = document.createElement('input');
+ checkbox.setAttribute('type', 'checkbox');
+ getNode(aContainer).insertBefore(checkbox, getNode(aContainer).firstChild);
+
+ var button = document.createElement('input');
+ button.setAttribute('type', 'button');
+ getNode(aContainer).appendChild(button);
+ }
+
+ this.finalCheck = function prependAppend_finalCheck()
+ {
+ var accTree =
+ { SECTION: [ // container
+ { CHECKBUTTON: [ ] },
+ { ENTRY: [ ] },
+ { PUSHBUTTON: [ ] }
+ ] };
+ testAccessibleTree(aContainer, accTree);
+ }
+
+ this.getID = function prependAppend_getID()
+ {
+ return "prepends a child and appends a child";
+ }
+ }
+
+ function removeRemove(aContainer)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, aContainer)
+ ];
+
+ this.invoke = function removeRemove_invoke()
+ {
+ getNode(aContainer).removeChild(getNode(aContainer).firstChild);
+ }
+
+ this.finalCheck = function removeRemove_finalCheck()
+ {
+ var accTree =
+ { SECTION: [ // container
+ { PUSHBUTTON: [ ] }
+ ] };
+ testAccessibleTree(aContainer, accTree);
+ }
+
+ this.getID = function removeRemove_getID()
+ {
+ return "remove first and second children";
+ }
+ }
+
+ function insertInaccessibleAccessibleSiblings()
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, "c3")
+ ];
+
+ this.invoke = function insertInaccessibleAccessibleSiblings_invoke()
+ {
+ getNode("c3").appendChild(document.createElement("span"));
+ getNode("c3").appendChild(document.createElement("input"));
+ }
+
+ this.finalCheck = function insertInaccessibleAccessibleSiblings_finalCheck()
+ {
+ var accTree =
+ { SECTION: [ // container
+ { PUSHBUTTON: [
+ { TEXT_LEAF: [] }
+ ] },
+ { ENTRY: [ ] }
+ ] };
+ testAccessibleTree("c3", accTree);
+ }
+
+ this.getID = function insertInaccessibleAccessibleSiblings_getID()
+ {
+ return "insert inaccessible and then accessible siblings";
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Do tests
+ ////////////////////////////////////////////////////////////////////////////
+
+ var gQueue = null;
+ //gA11yEventDumpID = "eventdump"; // debug stuff
+ //gA11yEventDumpToConsole = true;
+
+ function doTests()
+ {
+ gQueue = new eventQueue();
+
+ gQueue.push(new prependAppend("c1"));
+ gQueue.push(new removeRemove("c2"));
+ gQueue.push(new insertInaccessibleAccessibleSiblings());
+
+ gQueue.invoke(); // Will call SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTests);
+ </script>
+</head>
+
+<body>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <div id="c1"><input></div>
+ <div id="c2"><span><input type="checkbox"><input></span><input type="button"></div>
+
+ <div id="c3"><input type="button" value="button"></div>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_hidden.html b/accessible/tests/mochitest/treeupdate/test_hidden.html
new file mode 100644
index 000000000..2adb9efeb
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_hidden.html
@@ -0,0 +1,135 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>@hidden attribute testing</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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Invokers
+ ////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Set @hidden attribute
+ */
+ function setHiddenAttr(aContainerID, aChildID)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, getNode(aContainerID))
+ ];
+
+ this.invoke = function setHiddenAttr_invoke()
+ {
+ var tree =
+ { SECTION: [
+ { ENTRY: [
+ ] }
+ ] };
+ testAccessibleTree(aContainerID, tree);
+
+ getNode(aChildID).setAttribute("hidden", "true");
+ }
+
+ this.finalCheck = function setHiddenAttr_finalCheck()
+ {
+ var tree =
+ { SECTION: [
+ ] };
+ testAccessibleTree(aContainerID, tree);
+ }
+
+ this.getID = function setHiddenAttr_getID()
+ {
+ return "Set @hidden attribute on input and test accessible tree for div";
+ }
+ }
+
+ /**
+ * Remove @hidden attribute
+ */
+ function removeHiddenAttr(aContainerID, aChildID)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, getNode(aContainerID))
+ ];
+
+ this.invoke = function removeHiddenAttr_invoke()
+ {
+ var tree =
+ { SECTION: [
+ ] };
+ testAccessibleTree(aContainerID, tree);
+
+ getNode(aChildID).removeAttribute("hidden");
+ }
+
+ this.finalCheck = function removeHiddenAttr_finalCheck()
+ {
+ var tree =
+ { SECTION: [
+ { ENTRY: [
+ ] }
+ ] };
+ testAccessibleTree(aContainerID, tree);
+ }
+
+ this.getID = function removeHiddenAttr_getID()
+ {
+ return "Remove @hidden attribute on input and test accessible tree for div";
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Test
+ ////////////////////////////////////////////////////////////////////////////
+
+ //gA11yEventDumpID = "eventdump"; // debug stuff
+ //gA11yEventDumpToConsole = true;
+
+ var gQueue = null;
+
+ function doTest()
+ {
+ gQueue = new eventQueue();
+
+ gQueue.push(new setHiddenAttr("container", "child"));
+ gQueue.push(new removeHiddenAttr("container", "child"));
+
+ gQueue.invoke(); // SimpleTest.finish() will be called in the end
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+
+ </script>
+
+</head>
+
+<body>
+
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <div id="container"><input id="child"></div>
+
+ <div id="eventdump"></div>
+
+</body>
+
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_imagemap.html b/accessible/tests/mochitest/treeupdate/test_imagemap.html
new file mode 100644
index 000000000..c7c06b3d1
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_imagemap.html
@@ -0,0 +1,442 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>HTML img map accessible tree update tests</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="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+ <script type="application/javascript"
+ src="../common.js"></script>
+ <script type="application/javascript"
+ src="../role.js"></script>
+ <script type="application/javascript"
+ src="../events.js"></script>
+
+ <script type="application/javascript">
+ function insertArea(aImageMapID, aMapID)
+ {
+ this.imageMap = getAccessible(aImageMapID);
+ this.mapNode = getNode(aMapID);
+
+ function getInsertedArea(aThisObj)
+ {
+ return aThisObj.imageMap.firstChild;
+ }
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_SHOW, getInsertedArea, this),
+ new invokerChecker(EVENT_REORDER, this.imageMap)
+ ];
+
+ this.invoke = function insertArea_invoke()
+ {
+ var areaElm = document.createElement("area");
+ areaElm.setAttribute("href",
+ "http://www.bbc.co.uk/radio4/atoz/index.shtml#a");
+ areaElm.setAttribute("coords", "0,0,13,14");
+ areaElm.setAttribute("alt", "a");
+ areaElm.setAttribute("shape", "rect");
+
+ this.mapNode.insertBefore(areaElm, this.mapNode.firstChild);
+ }
+
+ this.finalCheck = function insertArea_finalCheck()
+ {
+ var accTree =
+ { IMAGE_MAP: [
+ {
+ role: ROLE_LINK,
+ name: "a",
+ children: [ ]
+ },
+ {
+ role: ROLE_LINK,
+ name: "b",
+ children: [ ]
+ },
+ ] };
+ testAccessibleTree(this.imageMap, accTree);
+ }
+
+ this.getID = function insertArea_getID()
+ {
+ return "insert area element";
+ }
+ }
+
+ function appendArea(aImageMapID, aMapID)
+ {
+ this.imageMap = getAccessible(aImageMapID);
+ this.mapNode = getNode(aMapID);
+
+ function getAppendedArea(aThisObj)
+ {
+ return aThisObj.imageMap.lastChild;
+ }
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_SHOW, getAppendedArea, this),
+ new invokerChecker(EVENT_REORDER, this.imageMap)
+ ];
+
+ this.invoke = function appendArea_invoke()
+ {
+ var areaElm = document.createElement("area");
+ areaElm.setAttribute("href",
+ "http://www.bbc.co.uk/radio4/atoz/index.shtml#c");
+ areaElm.setAttribute("coords", "34,0,47,14");
+ areaElm.setAttribute("alt", "c");
+ areaElm.setAttribute("shape", "rect");
+
+ this.mapNode.appendChild(areaElm);
+ }
+
+ this.finalCheck = function appendArea_finalCheck()
+ {
+ var accTree =
+ { IMAGE_MAP: [
+ {
+ role: ROLE_LINK,
+ name: "a",
+ children: [ ]
+ },
+ {
+ role: ROLE_LINK,
+ name: "b",
+ children: [ ]
+ },
+ {
+ role: ROLE_LINK,
+ name: "c",
+ children: [ ]
+ }
+ ] };
+ testAccessibleTree(this.imageMap, accTree);
+ }
+
+ this.getID = function appendArea_getID()
+ {
+ return "append area element";
+ }
+ }
+
+ function removeArea(aImageMapID, aMapID)
+ {
+ this.imageMap = getAccessible(aImageMapID);
+ this.area = null;
+ this.mapNode = getNode(aMapID);
+
+ function getRemovedArea(aThisObj)
+ {
+ return aThisObj.area;
+ }
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getRemovedArea, this),
+ new invokerChecker(EVENT_REORDER, this.imageMap)
+ ];
+
+ this.invoke = function removeArea_invoke()
+ {
+ this.area = this.imageMap.firstChild;
+ this.mapNode.removeChild(this.mapNode.firstElementChild);
+ }
+
+ this.finalCheck = function removeArea_finalCheck()
+ {
+ var accTree =
+ { IMAGE_MAP: [
+ {
+ role: ROLE_LINK,
+ name: "b",
+ children: [ ]
+ },
+ {
+ role: ROLE_LINK,
+ name: "c",
+ children: [ ]
+ }
+ ] };
+ testAccessibleTree(this.imageMap, accTree);
+ }
+
+ this.getID = function removeArea_getID()
+ {
+ return "remove area element";
+ }
+ }
+
+ function removeNameOnMap(aImageMapContainerID, aImageMapID, aMapID)
+ {
+ this.container = getAccessible(aImageMapContainerID);
+ this.containerNode = this.container.DOMNode;
+ this.imageMap = getAccessible(aImageMapID);
+ this.imgNode = this.imageMap.DOMNode;
+ this.mapNode = getNode(aMapID);
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, this.imageMap),
+ new invokerChecker(EVENT_SHOW, this.imgNode),
+ new invokerChecker(EVENT_REORDER, this.container)
+ ];
+
+ this.invoke = function removeNameOnMap_invoke()
+ {
+ this.mapNode.removeAttribute("name");
+ }
+
+ this.finalCheck = function removeNameOnMap_finalCheck()
+ {
+ var accTree =
+ { SECTION: [
+ { GRAPHIC: [ ] }
+ ] };
+ testAccessibleTree(this.container, accTree);
+ }
+
+ this.getID = function removeNameOnMap_getID()
+ {
+ return "remove @name on map element";
+ }
+ }
+
+ function restoreNameOnMap(aImageMapContainerID, aImageMapID, aMapID)
+ {
+ this.container = getAccessible(aImageMapContainerID);
+ this.containerNode = this.container.DOMNode;
+ this.imageMap = null;
+ this.imgNode = getNode(aImageMapID);
+ this.mapNode = getNode(aMapID);
+
+ function getImageMap(aThisObj)
+ {
+ return aThisObj.imageMap;
+ }
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getImageMap, this),
+ new invokerChecker(EVENT_SHOW, this.imgNode),
+ new invokerChecker(EVENT_REORDER, this.container)
+ ];
+
+ this.invoke = function restoreNameOnMap_invoke()
+ {
+ this.imageMap = getAccessible(aImageMapID);
+ this.mapNode.setAttribute("name", "atoz_map");
+
+ // XXXhack: force repainting of the image (see bug 745788 for details).
+ waveOverImageMap(aImageMapID);
+ }
+
+ this.finalCheck = function removeNameOnMap_finalCheck()
+ {
+ var accTree =
+ { SECTION: [
+ { IMAGE_MAP: [
+ { LINK: [ ] },
+ { LINK: [ ] }
+ ] }
+ ] };
+ testAccessibleTree(this.container, accTree);
+ }
+
+ this.getID = function removeNameOnMap_getID()
+ {
+ return "restore @name on map element";
+ }
+ }
+
+ function removeMap(aImageMapContainerID, aImageMapID, aMapID)
+ {
+ this.container = getAccessible(aImageMapContainerID);
+ this.containerNode = this.container.DOMNode;
+ this.imageMap = null;
+ this.imgNode = getNode(aImageMapID);
+ this.mapNode = getNode(aMapID);
+
+ function getImageMap(aThisObj)
+ {
+ return aThisObj.imageMap;
+ }
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getImageMap, this),
+ new invokerChecker(EVENT_SHOW, this.imgNode),
+ new invokerChecker(EVENT_REORDER, this.container)
+ ];
+
+ this.invoke = function removeMap_invoke()
+ {
+ this.imageMap = getAccessible(aImageMapID);
+ this.mapNode.parentNode.removeChild(this.mapNode);
+ }
+
+ this.finalCheck = function removeMap_finalCheck()
+ {
+ var accTree =
+ { SECTION: [
+ { GRAPHIC: [ ] }
+ ] };
+ testAccessibleTree(this.container, accTree);
+ }
+
+ this.getID = function removeMap_getID()
+ {
+ return "remove map element";
+ }
+ }
+
+ function insertMap(aImageMapContainerID, aImageID)
+ {
+ this.container = getAccessible(aImageMapContainerID);
+ this.containerNode = this.container.DOMNode;
+ this.image = null;
+ this.imgMapNode = getNode(aImageID);
+
+ function getImage(aThisObj)
+ {
+ return aThisObj.image;
+ }
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getImage, this),
+ new invokerChecker(EVENT_SHOW, this.imgMapNode),
+ new invokerChecker(EVENT_REORDER, this.container)
+ ];
+
+ this.invoke = function insertMap_invoke()
+ {
+ this.image = getAccessible(aImageID);
+
+ var map = document.createElement("map");
+ map.setAttribute("name", "atoz_map");
+ map.setAttribute("id", "map");
+
+ var area = document.createElement("area")
+ area.setAttribute("href",
+ "http://www.bbc.co.uk/radio4/atoz/index.shtml#b");
+ area.setAttribute("coords", "17,0,30,14");
+ area.setAttribute("alt", "b");
+ area.setAttribute("shape", "rect");
+
+ map.appendChild(area);
+
+ this.containerNode.appendChild(map);
+ }
+
+ this.finalCheck = function insertMap_finalCheck()
+ {
+ var accTree =
+ { SECTION: [
+ { IMAGE_MAP: [
+ { LINK: [ ] }
+ ] }
+ ] };
+ testAccessibleTree(this.container, accTree);
+ }
+
+ this.getID = function insertMap_getID()
+ {
+ return "insert map element";
+ }
+ }
+
+ function hideImageMap(aContainerID, aImageID)
+ {
+ this.container = getAccessible(aContainerID);
+ this.imageMap = null;
+ this.imageMapNode = getNode(aImageID);
+
+ function getImageMap(aThisObj)
+ {
+ return aThisObj.imageMap;
+ }
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getImageMap, this),
+ new invokerChecker(EVENT_REORDER, aContainerID)
+ ];
+
+ this.invoke = function hideImageMap_invoke()
+ {
+ this.imageMap = getAccessible(this.imageMapNode);
+ this.imageMapNode.style.display = "none";
+ }
+
+ this.finalCheck = function hideImageMap_finalCheck()
+ {
+ var accTree =
+ { SECTION: [ ] };
+ testAccessibleTree(this.container, accTree);
+ }
+
+ this.getID = function hideImageMap_getID()
+ {
+ return "display:none image";
+ }
+ }
+
+ //gA11yEventDumpToConsole = true; // debug stuff
+ function doPreTest()
+ {
+ waitForImageMap("imgmap", doTest);
+ }
+
+ var gQueue = null;
+ function doTest()
+ {
+ gQueue = new eventQueue();
+
+ gQueue.push(new insertArea("imgmap", "map"));
+ gQueue.push(new appendArea("imgmap", "map"));
+ gQueue.push(new removeArea("imgmap", "map"));
+ gQueue.push(new removeNameOnMap("container", "imgmap", "map"));
+ gQueue.push(new restoreNameOnMap("container", "imgmap", "map"));
+ gQueue.push(new removeMap("container", "imgmap", "map"));
+ gQueue.push(new insertMap("container", "imgmap"));
+ gQueue.push(new hideImageMap("container", "imgmap"));
+
+ //enableLogging("tree"); // debug stuff
+ //gQueue.onFinish = function() { disableLogging("tree"); }
+
+ gQueue.invoke(); // Will call SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doPreTest);
+ </script>
+
+</head>
+<body>
+
+ <a target="_blank"
+ title="Image map accessible tree is not updated when image map is changed"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=732389">
+ Mozilla Bug 732389
+ </a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <map name="atoz_map" id="map">
+ <area href="http://www.bbc.co.uk/radio4/atoz/index.shtml#b"
+ coords="17,0,30,14" alt="b" shape="rect">
+ </map>
+
+ <div id="container">
+ <img id="imgmap" width="447" height="15"
+ usemap="#atoz_map"
+ src="../letters.gif"><!--
+ Important: no whitespace between the <img> and the </div>, so we
+ don't end up with textframes there, because those would be reflected
+ in our accessible tree in some cases.
+ --></div>
+
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_list.html b/accessible/tests/mochitest/treeupdate/test_list.html
new file mode 100644
index 000000000..9196142d9
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_list.html
@@ -0,0 +1,152 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Test HTML li and listitem bullet accessible cache</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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Helpers
+
+ function testLiAccessibleTree()
+ {
+ // Test accessible tree.
+ var accTree = {
+ role: ROLE_LISTITEM,
+ children: [
+ {
+ role: ROLE_STATICTEXT,
+ children: []
+ },
+ {
+ role: ROLE_TEXT_LEAF,
+ children: []
+ }
+ ]
+ };
+
+ testAccessibleTree("li", accTree);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Sequence item processors
+
+ function hideProcessor()
+ {
+ this.liNode = getNode("li");
+ this.li = getAccessible(this.liNode);
+ this.bullet = this.li.firstChild;
+
+ this.process = function hideProcessor_process()
+ {
+ this.liNode.style.display = "none";
+ }
+
+ this.onProcessed = function hideProcessor_onProcessed()
+ {
+ window.setTimeout(
+ function(aLiAcc, aLiNode, aBulletAcc)
+ {
+ testDefunctAccessible(aLiAcc, aLiNode);
+ testDefunctAccessible(aBulletAcc);
+
+ gSequence.processNext();
+ },
+ 0, this.li, this.liNode, this.bullet
+ );
+ }
+ };
+
+ function showProcessor()
+ {
+ this.liNode = getNode("li");
+
+ this.process = function showProcessor_process()
+ {
+ this.liNode.style.display = "list-item";
+ }
+
+ this.onProcessed = function showProcessor_onProcessed()
+ {
+ testLiAccessibleTree();
+ gSequence.processNext();
+ }
+ };
+
+ function textReplaceProcessor()
+ {
+ this.liNode = getNode("li");
+
+ this.process = function textReplaceProcessor_process()
+ {
+ this.liNode.textContent = "hey";
+ }
+
+ this.onProcessed = function textReplaceProcessor_onProcessed()
+ {
+ var tree = {
+ LISTITEM: [
+ { STATICTEXT: [] },
+ { TEXT_LEAF: [] }
+ ]
+ };
+ testAccessibleTree(this.liNode, tree);
+ SimpleTest.finish();
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Test
+
+ //gA11yEventDumpToConsole = true;
+
+ var gSequence = null;
+ function doTest()
+ {
+ testLiAccessibleTree();
+
+ gSequence = new sequence();
+
+ gSequence.append(new hideProcessor(), EVENT_HIDE, getAccessible("li"),
+ "hide HTML li");
+ gSequence.append(new showProcessor(), EVENT_SHOW, getNode("li"),
+ "show HTML li");
+ gSequence.append(new textReplaceProcessor(), EVENT_REORDER, getNode("li"),
+ "change text of HTML li");
+
+ gSequence.processNext(); // SimpleTest.finish() will be called in the end
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank"
+ title="setParent shouldn't be virtual"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=496783">Mozilla Bug 496783</a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <ul>
+ <li id="li">item1</li>
+ </ul>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_list_editabledoc.html b/accessible/tests/mochitest/treeupdate/test_list_editabledoc.html
new file mode 100644
index 000000000..d4c178cb9
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_list_editabledoc.html
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Test HTML li and listitem bullet accessible insertion into editable document</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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Invokers
+
+ function addLi(aID)
+ {
+ this.listNode = getNode(aID);
+ this.liNode = document.createElement("li");
+ this.liNode.textContent = "item";
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_SHOW, getAccessible, this.liNode),
+ new invokerChecker(EVENT_REORDER, this.listNode)
+ ];
+
+ this.invoke = function addLi_invoke()
+ {
+ this.listNode.appendChild(this.liNode);
+ }
+
+ this.finalCheck = function addLi_finalCheck()
+ {
+ var tree = {
+ role: ROLE_LIST,
+ children: [
+ {
+ role: ROLE_LISTITEM,
+ children: [
+ {
+ role: ROLE_STATICTEXT,
+ name: "1. ",
+ children: []
+ },
+ {
+ role: ROLE_TEXT_LEAF,
+ children: []
+ }
+ ]
+ }
+ ]
+ };
+ testAccessibleTree(aID, tree);
+ }
+
+ this.getID = function addLi_getID()
+ {
+ return "add li";
+ }
+ };
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Test
+
+ //gA11yEventDumpID = "eventdump"; // debug stuff
+
+ var gQueue = null;
+
+ function doTest()
+ {
+ gQueue = new eventQueue();
+
+ gQueue.push(new addLi("list"));
+
+ gQueue.invoke(); // SimpleTest.finish() will be called in the end
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+</head>
+<body contentEditable="true">
+
+ <a target="_blank"
+ title="Wrong list bullet text of accessible for the first numbered HTML:li in CKEditor"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=557795">Mozilla Bug 557795</a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <ol id="list">
+ </ol>
+
+ <div id="eventdump"></div>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_listbox.xul b/accessible/tests/mochitest/treeupdate/test_listbox.xul
new file mode 100644
index 000000000..862b4dde8
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_listbox.xul
@@ -0,0 +1,180 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="Accessible XUL listbox hierarchy tests">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+
+ <script type="application/javascript"
+ src="../common.js" />
+ <script type="application/javascript"
+ src="../role.js" />
+ <script type="application/javascript"
+ src="../events.js" />
+
+ <script type="application/javascript">
+ <![CDATA[
+ ////////////////////////////////////////////////////////////////////////////
+ // Test
+
+ function insertListitem(aListboxID)
+ {
+ this.listboxNode = getNode(aListboxID);
+
+ this.listitemNode = document.createElement("listitem");
+ this.listitemNode.setAttribute("label", "item1");
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_SHOW, this.listitemNode),
+ new invokerChecker(EVENT_REORDER, this.listboxNode)
+ ];
+
+ this.invoke = function insertListitem_invoke()
+ {
+ this.listboxNode.insertBefore(this.listitemNode,
+ this.listboxNode.firstChild);
+ }
+
+ this.finalCheck = function insertListitem_finalCheck()
+ {
+ var tree =
+ { LISTBOX: [
+ {
+ role: ROLE_RICH_OPTION,
+ name: "item1"
+ },
+ {
+ role: ROLE_RICH_OPTION,
+ name: "item2"
+ },
+ {
+ role: ROLE_RICH_OPTION,
+ name: "item3"
+ },
+ {
+ role: ROLE_RICH_OPTION,
+ name: "item4"
+ }
+ ] };
+ testAccessibleTree(this.listboxNode, tree);
+ }
+
+ this.getID = function insertListitem_getID()
+ {
+ return "insert listitem ";
+ }
+ }
+
+ function removeListitem(aListboxID)
+ {
+ this.listboxNode = getNode(aListboxID);
+ this.listitemNode = null;
+ this.listitem;
+
+ function getListitem(aThisObj)
+ {
+ return aThisObj.listitem;
+ }
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getListitem, this),
+ new invokerChecker(EVENT_REORDER, this.listboxNode)
+ ];
+
+ this.invoke = function removeListitem_invoke()
+ {
+ this.listitemNode = this.listboxNode.firstChild;
+ this.listitem = getAccessible(this.listitemNode);
+
+ this.listboxNode.removeChild(this.listitemNode);
+ }
+
+ this.finalCheck = function removeListitem_finalCheck()
+ {
+ var tree =
+ { LISTBOX: [
+ {
+ role: ROLE_RICH_OPTION,
+ name: "item2"
+ },
+ {
+ role: ROLE_RICH_OPTION,
+ name: "item3"
+ },
+ {
+ role: ROLE_RICH_OPTION,
+ name: "item4"
+ }
+ ] };
+ testAccessibleTree(this.listboxNode, tree);
+ }
+
+ this.getID = function removeListitem_getID()
+ {
+ return "remove listitem ";
+ }
+ }
+
+ //gA11yEventDumpToConsole = true; // debug stuff
+
+ var gQueue = null;
+ function doTest()
+ {
+ var tree =
+ { LISTBOX: [
+ {
+ role: ROLE_RICH_OPTION,
+ name: "item2"
+ },
+ {
+ role: ROLE_RICH_OPTION,
+ name: "item3"
+ },
+ {
+ role: ROLE_RICH_OPTION,
+ name: "item4"
+ }
+ ] };
+ testAccessibleTree("listbox", tree);
+
+ gQueue = new eventQueue();
+ gQueue.push(new insertListitem("listbox"));
+ gQueue.push(new removeListitem("listbox"));
+ gQueue.invoke(); // Will call SimpleTest.finish()
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ ]]>
+ </script>
+
+ <hbox flex="1" style="overflow: auto;">
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=656225"
+ title="XUL listbox accessible tree doesn't get updated">
+ Mozilla Bug 656225
+ </a>
+ <br/>
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <vbox flex="1">
+ <listbox id="listbox" rows="2">
+ <listitem label="item2"/>
+ <listitem label="item3"/>
+ <listitem label="item4"/>
+ </listbox>
+ </vbox>
+ </hbox>
+
+</window>
+
diff --git a/accessible/tests/mochitest/treeupdate/test_menu.xul b/accessible/tests/mochitest/treeupdate/test_menu.xul
new file mode 100644
index 000000000..abdea217e
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_menu.xul
@@ -0,0 +1,128 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="Accessible XUL menu hierarchy tests">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+
+ <script type="application/javascript"
+ src="../common.js" />
+ <script type="application/javascript"
+ src="../role.js" />
+ <script type="application/javascript"
+ src="../events.js" />
+
+ <script type="application/javascript">
+ <![CDATA[
+ ////////////////////////////////////////////////////////////////////////////
+ // Invokers
+
+ function openMenu(aID)
+ {
+ this.menuNode = getNode(aID),
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_FOCUS, this.menuNode)
+ ];
+
+ this.invoke = function openMenu_invoke()
+ {
+ var tree;
+ if (LINUX || SOLARIS) {
+ tree =
+ { PARENT_MENUITEM: [ ] };
+
+ } else {
+ tree =
+ { PARENT_MENUITEM: [
+ { MENUPOPUP: [ ] }
+ ] };
+ }
+ testAccessibleTree(aID, tree);
+
+ // Show menu.
+ this.menuNode.open = true;
+ }
+
+ this.finalCheck = function openMenu_finalCheck()
+ {
+ var tree;
+ if (LINUX || SOLARIS) {
+ tree =
+ { PARENT_MENUITEM: [
+ { MENUITEM: [ ] },
+ { MENUITEM: [ ] }
+ ] };
+
+ } else {
+ tree =
+ { PARENT_MENUITEM: [
+ { MENUPOPUP: [
+ { MENUITEM: [ ] },
+ { MENUITEM: [ ] }
+ ] }
+ ] };
+ }
+ testAccessibleTree(aID, tree);
+ }
+
+ this.getID = function openMenu_getID()
+ {
+ return "open menu " + prettyName(aID);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Test
+
+ var gQueue = null;
+ function doTest()
+ {
+ gQueue = new eventQueue();
+ gQueue.push(new openMenu("menu"));
+ gQueue.invoke(); // Will call SimpleTest.finish();
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ ]]>
+ </script>
+
+ <hbox flex="1" style="overflow: auto;">
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=249292"
+ title="Ensure accessible children for toolbarbutton types 'menu' and 'menu-button'">
+ Mozilla Bug 249292
+ </a>
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=630486"
+ title="Don't force accessible creation for popup children.">
+ Mozilla Bug 630486
+ </a>
+ <br/>
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <vbox flex="1">
+ <menubar>
+ <menu id="menu" label="menu">
+ <menupopup>
+ <menuitem label="menuitem"/>
+ <menuitem label="menuitem"/>
+ </menupopup>
+ </menu>
+ </menubar>
+ </vbox>
+ </hbox>
+
+</window>
+
diff --git a/accessible/tests/mochitest/treeupdate/test_menubutton.xul b/accessible/tests/mochitest/treeupdate/test_menubutton.xul
new file mode 100644
index 000000000..4821a265b
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_menubutton.xul
@@ -0,0 +1,198 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="Accessible XUL button hierarchy tests">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
+
+ <script type="application/javascript"
+ src="../common.js" />
+ <script type="application/javascript"
+ src="../role.js" />
+ <script type="application/javascript"
+ src="../events.js" />
+
+ <script type="application/javascript">
+ <![CDATA[
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Invokers
+
+ function openMenu(aButtonID, aMenuItemRole)
+ {
+ var menuItemRole = aMenuItemRole || ROLE_MENUITEM;
+ this.button = getAccessible(aButtonID);
+ this.menupopup = this.button.firstChild;
+
+ var checker = new invokerChecker(EVENT_REORDER, this.menupopup);
+ this.__proto__ = new synthClick(aButtonID, checker);
+
+ this.invoke = function openMenu_invoke()
+ {
+ var tree =
+ { PUSHBUTTON: [
+ { MENUPOPUP: [ ] }
+ ] };
+ testAccessibleTree(this.button, tree);
+
+ this.__proto__.invoke();
+ }
+
+ this.finalCheck = function openMenu_finalCheck()
+ {
+ var tree =
+ { PUSHBUTTON: [
+ { MENUPOPUP: [
+ { role: menuItemRole, children: [ ] },
+ { role: menuItemRole, children: [ ] }
+ ] }
+ ] };
+ testAccessibleTree(this.button, tree);
+
+ synthesizeKey("VK_ESCAPE", { });
+ }
+
+ this.getID = function openMenu_getID()
+ {
+ return "open menu of the button " + prettyName(aButtonID);
+ }
+ }
+
+ function openMenuButton(aButtonID)
+ {
+ this.buttonNode = getNode(aButtonID);
+ this.menupoupNode = this.buttonNode.firstChild;
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, this.menupoupNode)
+ ];
+
+ this.invoke = function openMenu_invoke()
+ {
+ var tree =
+ { PUSHBUTTON: [
+ { MENUPOPUP: [ ] },
+ { PUSHBUTTON: [ ] }
+ ] };
+ testAccessibleTree(this.buttonNode, tree);
+
+ this.buttonNode.open = true;
+ }
+
+ this.finalCheck = function openMenu_finalCheck()
+ {
+ var tree =
+ { PUSHBUTTON: [
+ { MENUPOPUP: [
+ { MENUITEM: [ ] },
+ { MENUITEM: [ ] }
+ ] },
+ { PUSHBUTTON: [ ] }
+ ] };
+ testAccessibleTree(this.buttonNode, tree);
+
+ this.buttonNode.open = false;
+ }
+
+ this.getID = function openMenu_getID()
+ {
+ return "open menu for menu button " + prettyName(aButtonID);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Do test
+
+ gA11yEventDumpToConsole = true; // debug stuff
+
+ var gQueue = null;
+
+ function doTest()
+ {
+ gQueue = new eventQueue();
+
+ gQueue.push(new openMenu("button1"));
+ gQueue.push(new openMenuButton("button2"));
+ gQueue.push(new openMenu("button3"));
+ gQueue.push(new openMenuButton("button4"));
+
+ var columnPickerBtn = getAccessible("tree").firstChild.lastChild;
+ gQueue.push(new openMenu(columnPickerBtn, ROLE_CHECK_MENU_ITEM));
+ gQueue.invoke(); // SimpleTest.finish()
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ ]]>
+ </script>
+
+ <hbox flex="1" style="overflow: auto;">
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=249292"
+ title="Ensure accessible children for toolbarbutton types 'menu' and 'menu-button'">
+ Bug 249292
+ </a>
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=630486"
+ title="Don't force accessible creation for popup children">
+ Bug 630486
+ </a>
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=722265"
+ title="Column header selection popup no longer exposed to accessibility APIs">
+ Bug 722265
+ </a>
+ <br/>
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <vbox flex="1">
+ <button id="button1" type="menu" label="button">
+ <menupopup>
+ <menuitem label="menuitem"/>
+ <menuitem label="menuitem"/>
+ </menupopup>
+ </button>
+ <button id="button2" type="menu-button" label="menu button">
+ <menupopup>
+ <menuitem label="menuitem"/>
+ <menuitem label="menuitem"/>
+ </menupopup>
+ </button>
+
+ <toolbarbutton id="button3" type="menu" label="toolbarbutton">
+ <menupopup>
+ <menuitem label="menuitem"/>
+ <menuitem label="menuitem"/>
+ </menupopup>
+ </toolbarbutton>
+ <toolbarbutton id="button4" type="menu-button" label="menu toolbarbutton">
+ <menupopup>
+ <menuitem label="menuitem"/>
+ <menuitem label="menuitem"/>
+ </menupopup>
+ </toolbarbutton>
+
+ <tree id="tree" flex="1">
+ <treecols>
+ <treecol id="col" flex="1" primary="true" label="column"/>
+ <treecol id="col2" flex="1" label="another column"/>
+ </treecols>
+ <treechildren/>
+ </tree>
+ </vbox>
+ </hbox>
+
+</window>
+
diff --git a/accessible/tests/mochitest/treeupdate/test_optgroup.html b/accessible/tests/mochitest/treeupdate/test_optgroup.html
new file mode 100644
index 000000000..27323bbc3
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_optgroup.html
@@ -0,0 +1,137 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Add and remove optgroup test</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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ function addOptGroup(aID)
+ {
+ this.selectNode = getNode(aID);
+ this.select = getAccessible(this.selectNode);
+ this.selectList = this.select.firstChild;
+
+ this.invoke = function addOptGroup_invoke()
+ {
+ var optGroup = document.createElement("optgroup");
+ for (i = 0; i < 2; i++) {
+ var opt = document.createElement("option");
+ opt.value = i;
+ opt.text = "Option: Value " + i;
+
+ optGroup.appendChild(opt);
+ }
+
+ this.selectNode.add(optGroup, null);
+ var option = document.createElement("option");
+ this.selectNode.add(option, null);
+ }
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, this.selectList)
+ ];
+
+ this.finalCheck = function addOptGroup_finalCheck()
+ {
+ var tree =
+ { COMBOBOX: [
+ { COMBOBOX_LIST: [
+ { GROUPING: [
+ { COMBOBOX_OPTION: [
+ { TEXT_LEAF: [] }
+ ] },
+ { COMBOBOX_OPTION: [
+ { TEXT_LEAF: [] }
+ ] },
+ ]},
+ { COMBOBOX_OPTION: [] }
+ ] }
+ ] };
+ testAccessibleTree(this.select, tree);
+ }
+
+ this.getID = function addOptGroup_getID()
+ {
+ return "test optgroup's insertion into a select";
+ }
+ }
+
+ function removeOptGroup(aID)
+ {
+ this.selectNode = getNode(aID);
+ this.select = getAccessible(this.selectNode);
+ this.selectList = this.select.firstChild;
+
+ this.invoke = function removeOptGroup_invoke()
+ {
+ this.option1Node = this.selectNode.firstChild.firstChild;
+ this.selectNode.removeChild(this.selectNode.firstChild);
+ }
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, this.selectList)
+ ];
+
+ this.finalCheck = function removeOptGroup_finalCheck()
+ {
+ var tree =
+ { COMBOBOX: [
+ { COMBOBOX_LIST: [
+ { COMBOBOX_OPTION: [] }
+ ] }
+ ] };
+ testAccessibleTree(this.select, tree);
+ is(isAccessible(this.option1Node), false, "removed option shouldn't be accessible anymore!");
+ }
+
+ this.getID = function removeOptGroup_getID()
+ {
+ return "test optgroup's removal from a select";
+ }
+ }
+
+ //gA11yEventDumpToConsole = true;
+
+ function doTest()
+ {
+ gQueue = new eventQueue();
+
+ gQueue.push(new addOptGroup("select"));
+ gQueue.push(new removeOptGroup("select"));
+
+ gQueue.invoke(); // Will call SimpleTest.finish();
+
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=616452"
+ title="Bug 616452 - Dynamically inserted select options aren't reflected in accessible tree">
+ Bug 616452</a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <select id="select"></select>
+
+ <div id="debug"/>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_recreation.html b/accessible/tests/mochitest/treeupdate/test_recreation.html
new file mode 100644
index 000000000..7754eb703
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_recreation.html
@@ -0,0 +1,155 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Test accessible recreation</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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Invokers
+
+ function recreateAccessible(aID, aWontBeAccessible)
+ {
+ this.node = getNode(aID);
+ this.accessible =
+ isAccessible(this.node) ? getAccessible(this.node) : null;
+
+ this.eventSeq = [ ];
+
+ if (this.accessible)
+ this.eventSeq.push(new invokerChecker(EVENT_HIDE,
+ this.accessible));
+
+ if (!aWontBeAccessible)
+ this.eventSeq.push(new invokerChecker(EVENT_SHOW, getAccessible,
+ this.node));
+
+ this.eventSeq.push(new invokerChecker(EVENT_REORDER,
+ getContainerAccessible(this.node)));
+
+ if (this.accessible) {
+ this.unexpectedEventSeq = [
+ new invokerChecker(EVENT_SHOW, this.accessible)
+ ];
+ }
+ }
+
+ function changeAttr(aID, aAttr, aValue)
+ {
+ this.__proto__ = new recreateAccessible(aID);
+
+ this.invoke = function changeAttr_invoke()
+ {
+ this.node.setAttribute(aAttr, aValue);
+ }
+
+ this.getID = function changeAttr_getID()
+ {
+ return "change " + aAttr + "attribute for " + aID;
+ }
+ }
+
+ function removeAttr(aID, aAttr)
+ {
+ this.__proto__ = new recreateAccessible(aID, true);
+
+ this.invoke = function remvoeAttr_invoke()
+ {
+ this.node.removeAttribute(aAttr);
+ }
+
+ this.getID = function remvoeAttr_getID()
+ {
+ return "remove " + aAttr + "attribute for " + aID;
+ }
+ }
+
+ function changeRole(aID, aHasAccessible)
+ {
+ this.__proto__ = new changeAttr(aID, "role", "button");
+ }
+
+ function removeRole(aID)
+ {
+ this.__proto__ = new removeAttr(aID, "role");
+ }
+
+ function changeHref(aID)
+ {
+ this.__proto__ = new changeAttr(aID, "href", "www");
+ }
+
+ function changeMultiselectable(aID)
+ {
+ this.__proto__ = new changeAttr(aID, "aria-multiselectable", "true");
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Test
+
+ //gA11yEventDumpID = "eventdump"; // debug stuff
+ //gA11yEventDumpToConsole = true;
+
+ var gQueue = null;
+
+ function doTest()
+ {
+ gQueue = new eventQueue();
+
+ // make the accessible an inaccessible
+ gQueue.push(new changeRole("span"));
+
+ // make the inaccessible an accessible
+ gQueue.push(new removeRole("span"));
+
+ // recreate an accessible by role change
+ gQueue.push(new changeRole("div1"));
+
+ // recreate an accessible by href change
+ gQueue.push(new changeHref("anchor"));
+
+ // recreate an accessible by aria-multiselectable change
+ gQueue.push(new changeMultiselectable("div3"));
+
+ gQueue.invoke(); // SimpleTest.finish() will be called in the end
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank"
+ title="Rework accessible tree update code"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=570275">
+ Mozilla Bug 570275
+ </a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <span id="span">span</span>
+ <div id="div1">div</div>
+ <a id="anchor">anchor</a>
+ <div id="div3" role="listbox">list</div>
+
+ <div id="eventdump"></div>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_select.html b/accessible/tests/mochitest/treeupdate/test_select.html
new file mode 100644
index 000000000..006618b80
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_select.html
@@ -0,0 +1,130 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Add select options test</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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ function addOptions(aID)
+ {
+ this.selectNode = getNode(aID);
+ this.select = getAccessible(this.selectNode);
+ this.selectList = this.select.firstChild;
+
+ this.invoke = function addOptions_invoke()
+ {
+ for (i = 0; i < 2; i++) {
+ var opt = document.createElement("option");
+ opt.value = i;
+ opt.text = "Option: Value " + i;
+
+ this.selectNode.add(opt, null);
+ }
+ }
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, this.selectList)
+ ];
+
+ this.finalCheck = function addOptions_finalCheck()
+ {
+ var tree =
+ { COMBOBOX: [
+ { COMBOBOX_LIST: [
+ { COMBOBOX_OPTION: [
+ { TEXT_LEAF: [] }
+ ] },
+ { COMBOBOX_OPTION: [
+ { TEXT_LEAF: [] }
+ ] }
+ ] }
+ ] };
+ testAccessibleTree(this.select, tree);
+ }
+
+ this.getID = function addOptions_getID()
+ {
+ return "test elements insertion into a select";
+ }
+ }
+
+ function removeOptions(aID)
+ {
+ this.selectNode = getNode(aID);
+ this.select = getAccessible(this.selectNode);
+ this.selectList = this.select.firstChild;
+
+ this.invoke = function removeOptions_invoke()
+ {
+ while (this.selectNode.length)
+ this.selectNode.remove(0);
+ }
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, this.selectList)
+ ];
+
+ this.finalCheck = function removeOptions_finalCheck()
+ {
+ var tree =
+ { COMBOBOX: [
+ { COMBOBOX_LIST: [] }
+ ] };
+ testAccessibleTree(this.select, tree);
+ }
+
+ this.getID = function removeptions_getID()
+ {
+ return "test elements removal from a select";
+ }
+ }
+
+ //gA11yEventDumpID = "debug";
+
+ function doTest()
+ {
+ gQueue = new eventQueue();
+
+ gQueue.push(new addOptions("select"));
+ gQueue.push(new removeOptions("select"));
+
+ gQueue.invoke(); // Will call SimpleTest.finish();
+
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=616452"
+ title="Bug 616452 - Dynamically inserted select options aren't reflected in accessible tree">
+ Mozilla Bug 616452</a>
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=616940"
+ title="Removed select option accessibles aren't removed until hide event is fired">
+ Mozilla Bug 616940</a>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <select id="select"></select>
+
+ <div id="debug"/>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_shutdown.xul b/accessible/tests/mochitest/treeupdate/test_shutdown.xul
new file mode 100644
index 000000000..2e6f7a7b3
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_shutdown.xul
@@ -0,0 +1,132 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+ type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ title="Accessible XUL tree hierarchy tests">
+
+ <script type="application/javascript"
+ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+
+ <script type="application/javascript"
+ src="../treeview.js" />
+
+ <script type="application/javascript"
+ src="../common.js" />
+ <script type="application/javascript"
+ src="../role.js" />
+ <script type="application/javascript"
+ src="../states.js" />
+ <script type="application/javascript"
+ src="../events.js" />
+
+ <script type="application/javascript">
+ <![CDATA[
+ function setXULTreeView(aTreeID, aTreeView)
+ {
+ this.treeNode = getNode(aTreeID);
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, this.treeNode)
+ ];
+
+ this.invoke = function loadXULTree_invoke()
+ {
+ this.treeNode.view = aTreeView;
+ };
+
+ this.getID = function loadXULTree_getID()
+ {
+ return "Load XUL tree " + prettyName(aTreeID);
+ };
+ }
+
+ function removeTree(aID)
+ {
+ this.tree = getAccessible(aID);
+ this.lastItem = null;
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, document)
+ ];
+
+ this.invoke = function invoke()
+ {
+ this.lastItem = getAccessible(aID).lastChild;
+ this.lastCell = this.lastItem.lastChild;
+ getNode(aID).parentNode.removeChild(getNode(aID));
+ };
+
+ this.check = function check(aEvent)
+ {
+ testIsDefunct(this.tree, aID);
+ testIsDefunct(this.lastItem, "last item of " + aID);
+ if (this.lastCell) {
+ testIsDefunct(this.lastCell, "last item cell of " + aID);
+ }
+ };
+
+ this.getID = function getID()
+ {
+ return "Remove tree from DOM";
+ };
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Test
+
+ // gA11yEventDumpID = "debug";
+ var gQueue = null;
+
+ function doTest()
+ {
+ gQueue = new eventQueue();
+
+ gQueue.push(new setXULTreeView("tree", new nsTreeTreeView()));
+ gQueue.push(new removeTree("tree"));
+
+ gQueue.push(new setXULTreeView("treetable", new nsTreeTreeView()));
+ gQueue.push(new removeTree("treetable"));
+
+ gQueue.invoke(); // Will call SimpleTest.finish()
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ ]]>
+ </script>
+
+ <hbox flex="1" style="overflow: auto;">
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a target="_blank"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=503727"
+ title="Reorganize implementation of XUL tree accessibility">
+ Bug 503727
+ </a><br/>
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ </div>
+ <pre id="test">
+ </pre>
+ </body>
+
+ <vbox flex="1">
+ <tree id="tree" flex="1">
+ <treecols>
+ <treecol id="col" flex="1" primary="true" label="column"/>
+ </treecols>
+ <treechildren/>
+ </tree>
+
+ <tree id="treetable" flex="1">
+ <treecols>
+ <treecol id="col1" flex="1" primary="true" label="column"/>
+ <treecol id="col2" flex="1" label="column 2"/>
+ </treecols>
+ <treechildren/>
+ </tree>
+ </vbox>
+ </hbox>
+
+</window>
diff --git a/accessible/tests/mochitest/treeupdate/test_table.html b/accessible/tests/mochitest/treeupdate/test_table.html
new file mode 100644
index 000000000..abadefdb0
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_table.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Table update tests</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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ function appendCaption(aTableID)
+ {
+ this.invoke = function appendCaption_invoke()
+ {
+ // append a caption, it should appear as a first element in the
+ // accessible tree.
+ var caption = document.createElement("caption");
+ caption.textContent = "table caption";
+ getNode(aTableID).appendChild(caption);
+ }
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, aTableID)
+ ];
+
+ this.finalCheck = function appendCaption_finalCheck()
+ {
+ var tree =
+ { TABLE: [
+ { CAPTION: [
+ { TEXT_LEAF: [] }
+ ] },
+ { ROW: [
+ { CELL: [ {TEXT_LEAF: [] }]},
+ { CELL: [ {TEXT_LEAF: [] }]}
+ ] }
+ ] };
+ testAccessibleTree(aTableID, tree);
+ }
+
+ this.getID = function appendCaption_getID()
+ {
+ return "append caption";
+ }
+ }
+
+ function doTest()
+ {
+ gQueue = new eventQueue();
+ gQueue.push(new appendCaption("table"));
+ gQueue.invoke(); // Will call SimpleTest.finish();
+
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+</head>
+<body>
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <table id="table">
+ <tr>
+ <td>cell1</td>
+ <td>cell2</td>
+ </tr>
+ </table>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_textleaf.html b/accessible/tests/mochitest/treeupdate/test_textleaf.html
new file mode 100644
index 000000000..16d3a1a2b
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_textleaf.html
@@ -0,0 +1,180 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Test accessible recreation</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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Invokers
+
+ function textLeafUpdate(aID, aIsTextLeafLinkable)
+ {
+ this.node = getNode(aID);
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, this.node.parentNode)
+ ];
+
+ this.finalCheck = function textLeafUpdate_finalCheck()
+ {
+ var textLeaf = getAccessible(this.node).firstChild;
+ is(textLeaf.actionCount, (aIsTextLeafLinkable ? 1 : 0),
+ "Wrong action numbers!");
+ }
+ }
+
+ function setOnClickAttr(aID)
+ {
+ var node = getNode(aID);
+ node.setAttribute("onclick", "alert(3);");
+ var textLeaf = getAccessible(node).firstChild;
+ is(textLeaf.actionCount, 1, "setOnClickAttr: wrong action numbers!");
+ }
+
+ function removeOnClickAttr(aID)
+ {
+ var node = getNode(aID);
+ node.removeAttribute("onclick");
+ var textLeaf = getAccessible(node).firstChild;
+ is(textLeaf.actionCount, 0,
+ "removeOnClickAttr: wrong action numbers!");
+ }
+
+ function setOnClickNRoleAttrs(aID)
+ {
+ this.__proto__ = new textLeafUpdate(aID, true);
+
+ this.invoke = function setOnClickAttr_invoke()
+ {
+ this.node.setAttribute("role", "link");
+ this.node.setAttribute("onclick", "alert(3);");
+ }
+
+ this.getID = function setOnClickAttr_getID()
+ {
+ return "make " + prettyName(aID) + " linkable";
+ }
+ }
+
+ function removeTextData(aID, aRole)
+ {
+ this.containerNode = getNode(aID);
+ this.textNode = this.containerNode.firstChild;
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_REORDER, this.containerNode)
+ ];
+
+ this.invoke = function removeTextData_invoke()
+ {
+ var tree = {
+ role: aRole,
+ children: [
+ {
+ role: ROLE_TEXT_LEAF,
+ name: "text"
+ }
+ ]
+ };
+ testAccessibleTree(this.containerNode, tree);
+
+ this.textNode.data = "";
+ }
+
+ this.finalCheck = function removeTextData_finalCheck()
+ {
+ var tree = {
+ role: aRole,
+ children: []
+ };
+ testAccessibleTree(this.containerNode, tree);
+ }
+
+ this.getID = function removeTextData_finalCheck()
+ {
+ return "remove text data of text node inside '" + aID + "'.";
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Test
+
+ //gA11yEventDumpID = "eventdump"; // debug stuff
+ //gA11yEventDumpToConsole = true;
+
+ var gQueue = null;
+
+ function doTest()
+ {
+ // adds onclick on element, text leaf should inherit its action
+ setOnClickAttr("div");
+ // remove onclick attribute, text leaf shouldn't have any action
+ removeOnClickAttr("div");
+
+ // Call rest of event tests.
+ gQueue = new eventQueue();
+
+ // set onclick attribute making span accessible, it's inserted into tree
+ // and adopts text leaf accessible, text leaf should have an action
+ gQueue.push(new setOnClickNRoleAttrs("span"));
+
+ // text data removal of text node should remove its text accessible
+ gQueue.push(new removeTextData("p", ROLE_PARAGRAPH));
+ gQueue.push(new removeTextData("pre", ROLE_TEXT_CONTAINER));
+
+ gQueue.invoke(); // SimpleTest.finish() will be called in the end
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank"
+ title="Clean up the code of accessible initialization and binding to the tree"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=545465">
+ Mozilla Bug 545465
+ </a>
+ <a target="_blank"
+ title="Make sure accessible tree is correct when rendered text is changed"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=625652">
+ Mozilla Bug 625652
+ </a>
+ <a target="_blank"
+ title="Remove text accesible getting no text inside a preformatted area"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=706335">
+ Mozilla Bug 706335
+ </a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <div id="container">
+ <div id="div">div</div>
+ <span id="span">span</span>
+ </div>
+
+ <p id="p">text</p>
+ <pre id="pre">text</pre>
+
+ <div id="eventdump"></div>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_visibility.html b/accessible/tests/mochitest/treeupdate/test_visibility.html
new file mode 100644
index 000000000..a1c130fb6
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_visibility.html
@@ -0,0 +1,437 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Style visibility tree update test</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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Invokers
+
+ /**
+ * Hide parent while child stays visible.
+ */
+ function test1(aContainerID, aParentID, aChildID)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getNode(aParentID)),
+ new invokerChecker(EVENT_SHOW, getNode(aChildID)),
+ new invokerChecker(EVENT_REORDER, getNode(aContainerID))
+ ];
+
+ this.invoke = function invoke()
+ {
+ var tree =
+ { SECTION: [
+ { SECTION: [
+ { SECTION: [
+ { TEXT_LEAF: [] }
+ ] }
+ ] }
+ ] };
+ testAccessibleTree(aContainerID, tree);
+
+ getNode(aParentID).style.visibility = "hidden";
+ }
+
+ this.finalCheck = function finalCheck()
+ {
+ var tree =
+ { SECTION: [
+ { SECTION: [
+ { TEXT_LEAF: [] }
+ ] }
+ ] };
+ testAccessibleTree(aContainerID, tree);
+ }
+
+ this.getID = function getID()
+ {
+ return "hide parent while child stays visible";
+ }
+ }
+
+ /**
+ * Hide grand parent while its children stay visible.
+ */
+ function test2(aContainerID, aGrandParentID, aChildID, aChild2ID)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getNode(aGrandParentID)),
+ new invokerChecker(EVENT_SHOW, getNode(aChildID)),
+ new invokerChecker(EVENT_SHOW, getNode(aChild2ID)),
+ new invokerChecker(EVENT_REORDER, getNode(aContainerID))
+ ];
+
+ this.invoke = function invoke()
+ {
+ var tree =
+ { SECTION: [ // container
+ { SECTION: [ // grand parent
+ { SECTION: [
+ { SECTION: [ // child
+ { TEXT_LEAF: [] }
+ ] },
+ { SECTION: [ // child2
+ { TEXT_LEAF: [] }
+ ] }
+ ] }
+ ] }
+ ] };
+ testAccessibleTree(aContainerID, tree);
+
+ getNode(aGrandParentID).style.visibility = "hidden";
+ }
+
+ this.finalCheck = function finalCheck()
+ {
+ var tree =
+ { SECTION: [ // container
+ { SECTION: [ // child
+ { TEXT_LEAF: [] }
+ ] },
+ { SECTION: [ // child2
+ { TEXT_LEAF: [] }
+ ] }
+ ] };
+ testAccessibleTree(aContainerID, tree);
+ }
+
+ this.getID = function getID()
+ {
+ return "hide grand parent while its children stay visible";
+ }
+ }
+
+ /**
+ * Change container style, hide parents while their children stay visible.
+ */
+ function test3(aContainerID, aParentID, aParent2ID, aChildID, aChild2ID)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getNode(aParentID)),
+ new invokerChecker(EVENT_HIDE, getNode(aParent2ID)),
+ new invokerChecker(EVENT_SHOW, getNode(aChildID)),
+ new invokerChecker(EVENT_SHOW, getNode(aChild2ID)),
+ new invokerChecker(EVENT_REORDER, getNode(aContainerID))
+ ];
+
+ this.invoke = function invoke()
+ {
+ var tree =
+ { SECTION: [ // container
+ { SECTION: [ // parent
+ { SECTION: [ // child
+ { TEXT_LEAF: [] }
+ ] }
+ ] },
+ { SECTION: [ // parent2
+ { SECTION: [ // child2
+ { TEXT_LEAF: [] }
+ ] },
+ ] }
+ ] };
+ testAccessibleTree(aContainerID, tree);
+
+ getNode(aContainerID).style.color = "red";
+ getNode(aParentID).style.visibility = "hidden";
+ getNode(aParent2ID).style.visibility = "hidden";
+ }
+
+ this.finalCheck = function finalCheck()
+ {
+ var tree =
+ { SECTION: [ // container
+ { SECTION: [ // child
+ { TEXT_LEAF: [] }
+ ] },
+ { SECTION: [ // child2
+ { TEXT_LEAF: [] }
+ ] }
+ ] };
+ testAccessibleTree(aContainerID, tree);
+ }
+
+ this.getID = function getID()
+ {
+ return "change container style, hide parents while their children stay visible";
+ }
+ }
+
+ /**
+ * Change container style and make visible child inside the table.
+ */
+ function test4(aContainerID, aChildID)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_SHOW, getNode(aChildID)),
+ new invokerChecker(EVENT_REORDER, getNode(aChildID).parentNode)
+ ];
+
+ this.invoke = function invoke()
+ {
+ var tree =
+ { SECTION: [
+ { TABLE: [
+ { ROW: [
+ { CELL: [ ] }
+ ] }
+ ] }
+ ] };
+ testAccessibleTree(aContainerID, tree);
+
+ getNode(aContainerID).style.color = "red";
+ getNode(aChildID).style.visibility = "visible";
+ }
+
+ this.finalCheck = function finalCheck()
+ {
+ var tree =
+ { SECTION: [
+ { TABLE: [
+ { ROW: [
+ { CELL: [
+ { SECTION: [
+ { TEXT_LEAF: [] }
+ ] }
+ ] }
+ ] }
+ ] }
+ ] };
+ testAccessibleTree(aContainerID, tree);
+ }
+
+ this.getID = function getID()
+ {
+ return "change container style, make visible child insdie the table";
+ }
+ }
+
+ /**
+ * Hide subcontainer while child inside the table stays visible.
+ */
+ function test5(aContainerID, aSubContainerID, aChildID)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getNode(aSubContainerID)),
+ new invokerChecker(EVENT_SHOW, getNode(aChildID)),
+ new invokerChecker(EVENT_REORDER, getNode(aContainerID))
+ ];
+
+ this.invoke = function invoke()
+ {
+ var tree =
+ { SECTION: [ // container
+ { SECTION: [ // subcontainer
+ { TABLE: [
+ { ROW: [
+ { CELL: [
+ { SECTION: [ // child
+ { TEXT_LEAF: [] }
+ ] }
+ ] }
+ ] }
+ ] }
+ ] }
+ ] };
+ testAccessibleTree(aContainerID, tree);
+
+ getNode(aSubContainerID).style.visibility = "hidden";
+ }
+
+ this.finalCheck = function finalCheck()
+ {
+ var tree =
+ { SECTION: [ // container
+ { SECTION: [ // child
+ { TEXT_LEAF: [] }
+ ] }
+ ] };
+ testAccessibleTree(aContainerID, tree);
+ }
+
+ this.getID = function getID()
+ {
+ return "hide subcontainer while child inside the table stays visible";
+ }
+ }
+
+ /**
+ * Hide subcontainer while its child and child inside the nested table stays visible.
+ */
+ function test6(aContainerID, aSubContainerID, aChildID, aChild2ID)
+ {
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, getNode(aSubContainerID)),
+ new invokerChecker(EVENT_SHOW, getNode(aChildID)),
+ new invokerChecker(EVENT_SHOW, getNode(aChild2ID)),
+ new invokerChecker(EVENT_REORDER, getNode(aContainerID))
+ ];
+
+ this.invoke = function invoke()
+ {
+ var tree =
+ { SECTION: [ // container
+ { SECTION: [ // subcontainer
+ { TABLE: [
+ { ROW: [
+ { CELL: [
+ { TABLE: [ // nested table
+ { ROW: [
+ { CELL: [
+ { SECTION: [ // child
+ { TEXT_LEAF: [] } ]} ]} ]} ]} ]} ]} ]},
+ { SECTION: [ // child2
+ { TEXT_LEAF: [] } ]} ]} ]};
+
+ testAccessibleTree(aContainerID, tree);
+
+ // invoke
+ getNode(aSubContainerID).style.visibility = "hidden";
+ }
+
+ this.finalCheck = function finalCheck()
+ {
+ var tree =
+ { SECTION: [ // container
+ { SECTION: [ // child
+ { TEXT_LEAF: [] } ]},
+ { SECTION: [ // child2
+ { TEXT_LEAF: [] } ]} ]};
+
+ testAccessibleTree(aContainerID, tree);
+ }
+
+ this.getID = function getID()
+ {
+ return "hide subcontainer while its child and child inside the nested table stays visible";
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Test
+
+ //gA11yEventDumpID = "eventdump"; // debug stuff
+ //gA11yEventDumpToConsole = true;
+
+ var gQueue = null;
+
+ function doTest()
+ {
+ gQueue = new eventQueue();
+
+ gQueue.push(new test1("t1_container", "t1_parent", "t1_child"));
+ gQueue.push(new test2("t2_container", "t2_grandparent", "t2_child", "t2_child2"));
+ gQueue.push(new test3("t3_container", "t3_parent", "t3_parent2", "t3_child", "t3_child2"));
+ gQueue.push(new test4("t4_container", "t4_child"));
+ gQueue.push(new test5("t5_container", "t5_subcontainer", "t5_child"));
+ gQueue.push(new test6("t6_container", "t6_subcontainer", "t6_child", "t6_child2"));
+
+ gQueue.invoke(); // SimpleTest.finish() will be called in the end
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank"
+ title="Develop a way to handle visibility style"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=606125">
+ Mozilla Bug 606125
+ </a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <!-- hide parent while child stays visible -->
+ <div id="t1_container">
+ <div id="t1_parent">
+ <div id="t1_child" style="visibility: visible">text</div>
+ </div>
+ </div>
+
+ <!-- hide grandparent while its children stay visible -->
+ <div id="t2_container">
+ <div id="t2_grandparent">
+ <div>
+ <div id="t2_child" style="visibility: visible">text</div>
+ <div id="t2_child2" style="visibility: visible">text</div>
+ </div>
+ </div>
+ </div>
+
+ <!-- change container style, hide parents while their children stay visible -->
+ <div id="t3_container">
+ <div id="t3_parent">
+ <div id="t3_child" style="visibility: visible">text</div>
+ </div>
+ <div id="t3_parent2">
+ <div id="t3_child2" style="visibility: visible">text</div>
+ </div>
+ </div>
+
+ <!-- change container style, show child inside the table -->
+ <div id="t4_container">
+ <table>
+ <tr>
+ <td>
+ <div id="t4_child" style="visibility: hidden;">text</div>
+ </td>
+ </tr>
+ </table>
+ </div>
+
+ <!-- hide subcontainer while child inside the table stays visible -->
+ <div id="t5_container">
+ <div id="t5_subcontainer">
+ <table>
+ <tr>
+ <td>
+ <div id="t5_child" style="visibility: visible;">text</div>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+
+ <!-- hide subcontainer while its child and child inside the nested table stays visible -->
+ <div id="t6_container">
+ <div id="t6_subcontainer">
+ <table>
+ <tr>
+ <td>
+ <table>
+ <tr>
+ <td>
+ <div id="t6_child" style="visibility: visible;">text</div>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ <div id="t6_child2" style="visibility: visible">text</div>
+ </div>
+ </div>
+
+ <div id="eventdump"></div>
+</body>
+</html>
diff --git a/accessible/tests/mochitest/treeupdate/test_whitespace.html b/accessible/tests/mochitest/treeupdate/test_whitespace.html
new file mode 100644
index 000000000..e7ba9b059
--- /dev/null
+++ b/accessible/tests/mochitest/treeupdate/test_whitespace.html
@@ -0,0 +1,187 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Whitespace text accessible creation/desctruction</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="../events.js"></script>
+
+ <script type="application/javascript">
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Invokers
+
+ /**
+ * Middle image accessible removal results in text accessible removal.
+ *
+ * Before:
+ * DOM: whitespace img1 whitespace img2 whitespace img3 whitespace,
+ * a11y: img1 whitespace img2 whitespace img3
+ * After:
+ * DOM: whitespace img1 whitespace whitespace img3 whitespace,
+ * a11y: img1 whitespace img3
+ */
+ function removeImg()
+ {
+ this.containerNode = getNode("container1");
+ this.imgNode = getNode("img1");
+ this.img = getAccessible(this.imgNode);
+ this.text = this.img.nextSibling;
+
+ this.eventSeq = [
+ new invokerChecker(EVENT_HIDE, this.img),
+ new invokerChecker(EVENT_HIDE, this.text),
+ new invokerChecker(EVENT_REORDER, this.containerNode)
+ ];
+
+ this.finalCheck = function textLeafUpdate_finalCheck()
+ {
+ var tree =
+ { SECTION: [
+ { GRAPHIC: [] },
+ { TEXT_LEAF: [] },
+ { GRAPHIC: [] }
+ ] };
+
+ testAccessibleTree(this.containerNode, tree);
+ }
+
+ this.invoke = function setOnClickAttr_invoke()
+ {
+ var tree =
+ { SECTION: [
+ { GRAPHIC: [] },
+ { TEXT_LEAF: [] },
+ { GRAPHIC: [] },
+ { TEXT_LEAF: [] },
+ { GRAPHIC: [] }
+ ] };
+
+ testAccessibleTree(this.containerNode, tree);
+
+ this.containerNode.removeChild(this.imgNode);
+ }
+
+ this.getID = function setOnClickAttr_getID()
+ {
+ return "remove middle img";
+ }
+ }
+
+ /**
+ * Append image making the whitespace visible and thus accessible.
+ * Note: images and whitespaces are on different leves of accessible trees,
+ * so that image container accessible update doesn't update the tree
+ * of whitespace container.
+ *
+ * Before:
+ * DOM: whitespace emptylink whitespace linkwithimg whitespace
+ * a11y: emptylink linkwithimg
+ * After:
+ * DOM: whitespace linkwithimg whitespace linkwithimg whitespace
+ * a11y: linkwithimg whitespace linkwithimg
+ */
+ function insertImg()
+ {
+ this.containerNode = getNode("container2");
+ this.topNode = this.containerNode.parentNode;
+ this.textNode = this.containerNode.nextSibling;
+ this.imgNode = document.createElement("img");
+ this.imgNode.setAttribute("src", "../moz.png");
+
+ this.eventSeq = [
+ new asyncInvokerChecker(EVENT_SHOW, getAccessible, this.textNode),
+ new asyncInvokerChecker(EVENT_SHOW, getAccessible, this.imgNode),
+ new orderChecker(),
+ new invokerChecker(EVENT_REORDER, this.topNode)
+ ];
+
+ this.invoke = function insertImg_invoke()
+ {
+ var tree =
+ { SECTION: [
+ { LINK: [] },
+ { LINK: [
+ { GRAPHIC: [] }
+ ] }
+ ] };
+
+ testAccessibleTree(this.topNode, tree);
+
+ this.containerNode.appendChild(this.imgNode);
+ }
+
+ this.finalCheck = function insertImg_finalCheck()
+ {
+ var tree =
+ { SECTION: [
+ { LINK: [
+ { GRAPHIC: [ ] }
+ ] },
+ { TEXT_LEAF: [ ] },
+ { LINK: [
+ { GRAPHIC: [ ] }
+ ] }
+ ] };
+
+ testAccessibleTree(this.topNode, tree);
+ }
+
+ this.getID = function appendImg_getID()
+ {
+ return "insert img into internal container";
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Test
+
+ //gA11yEventDumpID = "eventdump"; // debug stuff
+ //gA11yEventDumpToConsole = true;
+
+ var gQueue = null;
+
+ function doTest()
+ {
+ gQueue = new eventQueue();
+
+ gQueue.push(new removeImg());
+ gQueue.push(new insertImg());
+
+ gQueue.invoke(); // SimpleTest.finish() will be called in the end
+ }
+
+ SimpleTest.waitForExplicitFinish();
+ addA11yLoadEvent(doTest);
+ </script>
+</head>
+<body>
+
+ <a target="_blank"
+ title="Make sure accessible tree is correct when rendered text is changed"
+ href="https://bugzilla.mozilla.org/show_bug.cgi?id=625652">
+ Mozilla Bug 625652
+ </a>
+
+ <p id="display"></p>
+ <div id="content" style="display: none"></div>
+ <pre id="test">
+ </pre>
+
+ <div id="container1"> <img src="../moz.png"> <img id="img1" src="../moz.png"> <img src="../moz.png"> </div>
+ <div> <a id="container2"></a> <a><img src="../moz.png"></a> </div>
+
+ <div id="eventdump"></div>
+</body>
+</html>