diff options
Diffstat (limited to '')
-rw-r--r-- | widget/tests/native_menus_window.xhtml | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/widget/tests/native_menus_window.xhtml b/widget/tests/native_menus_window.xhtml new file mode 100644 index 0000000000..2b3d3f2aa3 --- /dev/null +++ b/widget/tests/native_menus_window.xhtml @@ -0,0 +1,282 @@ +<?xml version="1.0"?> + +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> + +<window id="NativeMenuWindow" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + width="300" + height="300" + onload="onLoad();" + title="Native Menu Test"> + + <command id="cmd_FooItem0" oncommand="executedCommandID = 'cmd_FooItem0';"/> + <command id="cmd_FooItem1" oncommand="executedCommandID = 'cmd_FooItem1';"/> + <command id="cmd_BarItem0" oncommand="executedCommandID = 'cmd_BarItem0';"/> + <command id="cmd_BarItem1" oncommand="executedCommandID = 'cmd_BarItem1';"/> + <command id="cmd_NewItem0" oncommand="executedCommandID = 'cmd_NewItem0';"/> + <command id="cmd_NewItem1" oncommand="executedCommandID = 'cmd_NewItem1';"/> + <command id="cmd_NewItem2" oncommand="executedCommandID = 'cmd_NewItem2';"/> + <command id="cmd_NewItem3" oncommand="executedCommandID = 'cmd_NewItem3';"/> + <command id="cmd_NewItem4" oncommand="executedCommandID = 'cmd_NewItem4';"/> + <command id="cmd_NewItem5" oncommand="executedCommandID = 'cmd_NewItem5';"/> + + <!-- We do not modify any menus or menu items defined here in testing. These + serve as a baseline structure for us to test after other modifications. + We add children to the menubar defined here and test by modifying those + children. --> + <menubar id="nativemenubar"> + <menu id="foo" label="Foo"> + <menupopup> + <menuitem label="FooItem0" command="cmd_FooItem0"/> + <menuitem label="FooItem1" command="cmd_FooItem1"/> + <menuseparator/> + <menu label="Bar"> + <menupopup> + <menuitem label="BarItem0" command="cmd_BarItem0"/> + <menuitem label="BarItem1" command="cmd_BarItem1"/> + </menupopup> + </menu> + </menupopup> + </menu> + </menubar> + + <script type="application/javascript"><![CDATA[ + + function ok(condition, message) { + window.arguments[0].SimpleTest.ok(condition, message); + } + + function onTestsFinished() { + window.close(); + window.arguments[0].SimpleTest.finish(); + } + + // Force a menu to update itself. All of the menus parents will be updated + // as well. An empty string will force a complete menu system reload. + function forceUpdateNativeMenuAt(location) { + var utils = window.windowUtils; + try { + utils.forceUpdateNativeMenuAt(location); + } + catch (e) { + dump(e + "\n"); + } + } + + var executedCommandID = ""; + + function testItem(location, targetID) { + var utils = window.windowUtils; + var correctCommandHandler = false; + try { + utils.activateNativeMenuItemAt(location); + correctCommandHandler = executedCommandID == targetID; + } + catch (e) { + dump(e + "\n"); + } + finally { + executedCommandID = ""; + } + return correctCommandHandler; + } + + function createXULMenuPopup() { + const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + var item = document.createElementNS(XUL_NS, "menupopup"); + return item; + } + + function createXULMenu(aLabel) { + const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + var item = document.createElementNS(XUL_NS, "menu"); + item.setAttribute("label", aLabel); + return item; + } + + function createXULMenuItem(aLabel, aCommandId) { + const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + var item = document.createElementNS(XUL_NS, "menuitem"); + item.setAttribute("label", aLabel); + item.setAttribute("command", aCommandId); + return item; + } + + function runBaseMenuTests() { + forceUpdateNativeMenuAt("0|3"); + return testItem("0|0", "cmd_FooItem0") && + testItem("0|1", "cmd_FooItem1") && + testItem("0|3|0", "cmd_BarItem0") && + testItem("0|3|1", "cmd_BarItem1"); + } + + function onLoad() { + var _delayedOnLoad = function() { + // First let's run the base menu tests. + ok(runBaseMenuTests()); + + // Set up some nodes that we'll use. + var menubarNode = document.getElementById("nativemenubar"); + var newMenu0 = createXULMenu("NewMenu0"); + var newMenu1 = createXULMenu("NewMenu1"); + var newMenuPopup0 = createXULMenuPopup(); + var newMenuPopup1 = createXULMenuPopup(); + var newMenuItem0 = createXULMenuItem("NewMenuItem0", "cmd_NewItem0"); + var newMenuItem1 = createXULMenuItem("NewMenuItem1", "cmd_NewItem1"); + var newMenuItem2 = createXULMenuItem("NewMenuItem2", "cmd_NewItem2"); + var newMenuItem3 = createXULMenuItem("NewMenuItem3", "cmd_NewItem3"); + var newMenuItem4 = createXULMenuItem("NewMenuItem4", "cmd_NewItem4"); + var newMenuItem5 = createXULMenuItem("NewMenuItem5", "cmd_NewItem5"); + + // Create another submenu with hierarchy via DOM manipulation. + // ****************** + // * Foo * NewMenu0 * <- Menu bar + // ****************** + // **************** + // * NewMenuItem0 * <- NewMenu0 submenu + // **************** + // * NewMenuItem1 * + // **************** + // * NewMenuItem2 * + // ******************************* + // * NewMenu1 > * NewMenuItem3 * <- NewMenu1 submenu + // ******************************* + // * NewMenuItem4 * + // **************** + // * NewMenuItem5 * + // **************** + newMenu0.appendChild(newMenuPopup0); + newMenuPopup0.appendChild(newMenuItem0); + newMenuPopup0.appendChild(newMenuItem1); + newMenuPopup0.appendChild(newMenuItem2); + newMenuPopup0.appendChild(newMenu1); + newMenu1.appendChild(newMenuPopup1); + newMenuPopup1.appendChild(newMenuItem3); + newMenuPopup1.appendChild(newMenuItem4); + newMenuPopup1.appendChild(newMenuItem5); + //XXX - we have to append the menu to the top-level of the menu bar + // only after constructing it. If we append before construction, it is + // invalid because it has no children and we don't validate it if we add + // children later. + menubarNode.appendChild(newMenu0); + forceUpdateNativeMenuAt("1|3"); + // Run basic tests again. + ok(runBaseMenuTests()); + + // Error strings. + var sa = "Command handler(s) should have activated"; + var sna = "Command handler(s) should not have activated"; + + // Test middle items. + ok(testItem("1|1", "cmd_NewItem1"), sa); + ok(testItem("1|3|1", "cmd_NewItem4"), sa); + + // Hide newMenu0. + newMenu0.setAttribute("hidden", "true"); + ok(runBaseMenuTests(), sa); // the base menu should still be unhidden + ok(!testItem("1|0", ""), sna); + ok(!testItem("1|1", ""), sna); + ok(!testItem("1|2", ""), sna); + ok(!testItem("1|3|0", ""), sna); + ok(!testItem("1|3|1", ""), sna); + ok(!testItem("1|3|2", ""), sna); + + // Show newMenu0. + newMenu0.setAttribute("hidden", "false"); + forceUpdateNativeMenuAt("1|3"); + ok(runBaseMenuTests(), sa); + ok(testItem("1|0", "cmd_NewItem0"), sa); + ok(testItem("1|1", "cmd_NewItem1"), sa); + ok(testItem("1|2", "cmd_NewItem2"), sa); + ok(testItem("1|3|0", "cmd_NewItem3"), sa); + ok(testItem("1|3|1", "cmd_NewItem4"), sa); + ok(testItem("1|3|2", "cmd_NewItem5"), sa); + + // Hide items. + newMenuItem1.setAttribute("hidden", "true"); + newMenuItem4.setAttribute("hidden", "true"); + forceUpdateNativeMenuAt("1|2"); + ok(runBaseMenuTests(), sa); + ok(testItem("1|0", "cmd_NewItem0"), sa); + ok(testItem("1|1", "cmd_NewItem2"), sa); + ok(!testItem("1|2", ""), sna); + ok(testItem("1|2|0", "cmd_NewItem3"), sa); + ok(testItem("1|2|1", "cmd_NewItem5"), sa); + ok(!testItem("1|2|2", ""), sna); + + // Show items. + newMenuItem1.setAttribute("hidden", "false"); + newMenuItem4.setAttribute("hidden", "false"); + forceUpdateNativeMenuAt("1|3"); + ok(runBaseMenuTests(), sa); + ok(testItem("1|0", "cmd_NewItem0"), sa); + ok(testItem("1|1", "cmd_NewItem1"), sa); + ok(testItem("1|2", "cmd_NewItem2"), sa); + ok(testItem("1|3|0", "cmd_NewItem3"), sa); + ok(testItem("1|3|1", "cmd_NewItem4"), sa); + ok(testItem("1|3|2", "cmd_NewItem5"), sa); + + // At this point in the tests the state of the menus has been returned + // to the originally diagramed state. + + // Test command disabling + var cmd_NewItem0 = document.getElementById("cmd_NewItem0"); + ok(testItem("1|0", "cmd_NewItem0"), sa); + cmd_NewItem0.setAttribute("disabled", "true"); + ok(!testItem("1|0", "cmd_NewItem0"), sna); + cmd_NewItem0.removeAttribute("disabled"); + ok(testItem("1|0", "cmd_NewItem0"), sa); + + // Remove menu. + menubarNode.removeChild(newMenu0); + ok(runBaseMenuTests(), sa); + ok(!testItem("1|0", ""), sna); + ok(!testItem("1|1", ""), sna); + ok(!testItem("1|2", ""), sna); + ok(!testItem("1|3|0", ""), sna); + ok(!testItem("1|3|1", ""), sna); + ok(!testItem("1|3|2", ""), sna); + // return state to original diagramed state + menubarNode.appendChild(newMenu0); + + // Test for bug 447042, make sure that adding a menu node with no children + // to the menu bar and then adding another menu node with children works. + // Menus with no children don't get their native menu items shown and that + // caused internal arrays to get out of sync and an append crashed. + var tmpMenu0 = createXULMenu("tmpMenu0"); + menubarNode.removeChild(newMenu0); + menubarNode.appendChild(tmpMenu0); + menubarNode.appendChild(newMenu0); + forceUpdateNativeMenuAt("1|3"); + ok(runBaseMenuTests()); + ok(testItem("1|0", "cmd_NewItem0"), sa); + ok(testItem("1|1", "cmd_NewItem1"), sa); + ok(testItem("1|2", "cmd_NewItem2"), sa); + ok(testItem("1|3|0", "cmd_NewItem3"), sa); + ok(testItem("1|3|1", "cmd_NewItem4"), sa); + ok(testItem("1|3|2", "cmd_NewItem5"), sa); + // return state to original diagramed state + menubarNode.removeChild(tmpMenu0); + + // This test is basically a crash test for bug 433858. + newMenuItem1.setAttribute("hidden", "true"); + newMenuItem2.setAttribute("hidden", "true"); + newMenu1.setAttribute("hidden", "true"); + forceUpdateNativeMenuAt("1"); + newMenuItem1.setAttribute("hidden", "false"); + newMenuItem2.setAttribute("hidden", "false"); + newMenu1.setAttribute("hidden", "false"); + forceUpdateNativeMenuAt("1"); + + onTestsFinished(); + } + + setTimeout(_delayedOnLoad, 1000); + } + + ]]></script> +</window> |