3 <?xml-stylesheet href=
"chrome://global/skin" type=
"text/css"?>
5 <window id=
"StandaloneNativeMenuWindow"
6 xmlns=
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
10 title=
"nsIStandaloneNativeMenu Test">
12 <command id=
"cmd_FooItem0" oncommand=
"executedCommandID = 'cmd_FooItem0';"/>
13 <command id=
"cmd_FooItem1" oncommand=
"executedCommandID = 'cmd_FooItem1';"/>
14 <command id=
"cmd_BarItem0" oncommand=
"executedCommandID = 'cmd_BarItem0';"/>
15 <command id=
"cmd_BarItem1" oncommand=
"executedCommandID = 'cmd_BarItem1';"/>
16 <command id=
"cmd_NewItem0" oncommand=
"executedCommandID = 'cmd_NewItem0';"/>
17 <command id=
"cmd_NewItem1" oncommand=
"executedCommandID = 'cmd_NewItem1';"/>
18 <command id=
"cmd_NewItem2" oncommand=
"executedCommandID = 'cmd_NewItem2';"/>
19 <command id=
"cmd_NewItem3" oncommand=
"executedCommandID = 'cmd_NewItem3';"/>
20 <command id=
"cmd_NewItem4" oncommand=
"executedCommandID = 'cmd_NewItem4';"/>
21 <command id=
"cmd_NewItem5" oncommand=
"executedCommandID = 'cmd_NewItem5';"/>
23 <!-- We do not modify any menus or menu items defined here in testing. These
24 serve as a baseline structure for us to test after other modifications.
25 We add children to the menubar defined here and test by modifying those
28 <menupopup id=
"standalonenativemenu">
29 <menu id=
"foo" label=
"Foo">
31 <menuitem label=
"FooItem0" command=
"cmd_FooItem0"/>
32 <menuitem label=
"FooItem1" command=
"cmd_FooItem1"/>
36 <menuitem label=
"BarItem0" command=
"cmd_BarItem0"/>
37 <menuitem label=
"BarItem1" command=
"cmd_BarItem1"/>
45 <script type=
"application/javascript"><![CDATA[
47 function ok(condition, message) {
48 window.opener.wrappedJSObject.SimpleTest.ok(condition, message);
51 function todo(condition, message) {
52 window.opener.wrappedJSObject.SimpleTest.todo(condition, message);
55 function onTestsFinished() {
57 window.opener.wrappedJSObject.SimpleTest.finish();
60 var executedCommandID =
"";
62 function testItem(menu, location, targetID) {
63 var correctCommandHandler = false;
66 menu.activateNativeMenuItemAt(location);
67 correctCommandHandler = executedCommandID == targetID;
73 executedCommandID =
"";
74 return correctCommandHandler;
78 var XUL_NS =
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
80 function createXULMenuPopup() {
81 return document.createElementNS(XUL_NS,
"menupopup");
84 function createXULMenu(aLabel) {
85 var item = document.createElementNS(XUL_NS,
"menu");
86 item.setAttribute(
"label", aLabel);
90 function createXULMenuItem(aLabel, aCommandId) {
91 var item = document.createElementNS(XUL_NS,
"menuitem");
92 item.setAttribute(
"label", aLabel);
93 item.setAttribute(
"command", aCommandId);
97 function runBaseMenuTests(menu) {
98 menu.forceUpdateNativeMenuAt(
"0|3");
99 return testItem(menu,
"0|0",
"cmd_FooItem0") &&
100 testItem(menu,
"0|1",
"cmd_FooItem1") &&
101 testItem(menu,
"0|3|0",
"cmd_BarItem0") &&
102 testItem(menu,
"0|3|1",
"cmd_BarItem1");
105 function createStandaloneNativeMenu(menuNode) {
107 let menu = Cc[
"@mozilla.org/widget/standalonenativemenu;1"].createInstance(Ci.nsIStandaloneNativeMenu);
111 ok(false,
"Failed creating nsIStandaloneNativeMenu instance");
116 function runDetachedMenuTests(addMenupopupBeforeCreatingSNM) {
117 let menu = createXULMenu(
"Detached menu");
118 menu.setAttribute(
"image", 'data:image/svg+xml,
<svg%
20xmlns=
"http://www.w3.org/2000/svg"%
20width=
"32"%
20height=
"32"><circle%
20cx=
"16"%
20cy=
"16"%
20r=
"16"/></svg>');
119 let menupopup = createXULMenuPopup();
121 let popupShowingFired = false;
122 let itemActivated = false;
124 menupopup.addEventListener(
"popupshowing", function (e) {
125 popupShowingFired = true;
127 let menuitem = document.createElementNS(XUL_NS,
"menuitem");
128 menuitem.setAttribute(
"label",
"detached menu item");
129 menuitem.addEventListener(
"command", function (e) {
130 itemActivated = true;
132 menupopup.appendChild(menuitem);
135 // It shouldn't make a difference whether the menupopup is added to the
136 // menu element before or after we create the nsIStandaloneNativeMenu
137 // instance with it. We test both orders by calling this function twice
138 // with different values for addMenupopupBeforeCreatingSNM.
140 var menuSNM = null; // the nsIStandaloneNativeMenu object for
"menu"
141 if (addMenupopupBeforeCreatingSNM) {
142 menu.appendChild(menupopup);
143 menuSNM = createStandaloneNativeMenu(menu);
145 menuSNM = createStandaloneNativeMenu(menu);
146 menu.appendChild(menupopup);
150 ok(!popupShowingFired,
"popupshowing shouldn't have fired before our call to menuWillOpen()");
151 menuSNM.menuWillOpen();
152 ok(popupShowingFired,
"calling menuWillOpen() should have notified our popupshowing listener");
154 ok(!itemActivated,
"our dynamically-added menuitem shouldn't have been activated yet");
155 menuSNM.activateNativeMenuItemAt(
"0");
156 ok(itemActivated,
"the new menu item should have been activated now");
158 ok(false,
"dynamic menu test failed: " + ex);
163 var _delayedOnLoad = function() {
166 var menuNode = document.getElementById(
"standalonenativemenu");
167 var menu = createStandaloneNativeMenu(menuNode);
169 // First let's run the base menu tests.
170 ok(runBaseMenuTests(menu),
"base tests #1");
172 // Set up some nodes that we'll use.
173 var newMenu0 = createXULMenu(
"NewMenu0");
174 var newMenu1 = createXULMenu(
"NewMenu1");
175 var newMenuPopup0 = createXULMenuPopup();
176 var newMenuPopup1 = createXULMenuPopup();
177 var newMenuItem0 = createXULMenuItem(
"NewMenuItem0",
"cmd_NewItem0");
178 var newMenuItem1 = createXULMenuItem(
"NewMenuItem1",
"cmd_NewItem1");
179 var newMenuItem2 = createXULMenuItem(
"NewMenuItem2",
"cmd_NewItem2");
180 var newMenuItem3 = createXULMenuItem(
"NewMenuItem3",
"cmd_NewItem3");
181 var newMenuItem4 = createXULMenuItem(
"NewMenuItem4",
"cmd_NewItem4");
182 var newMenuItem5 = createXULMenuItem(
"NewMenuItem5",
"cmd_NewItem5");
184 // Create another submenu with hierarchy via DOM manipulation.
185 // ******************
186 // * Foo * NewMenu0 *
<- Menu bar
187 // ******************
189 // * NewMenuItem0 *
<- NewMenu0 submenu
194 // *******************************
195 // * NewMenu1
> * NewMenuItem3 *
<- NewMenu1 submenu
196 // *******************************
201 newMenu0.appendChild(newMenuPopup0);
202 newMenuPopup0.appendChild(newMenuItem0);
203 newMenuPopup0.appendChild(newMenuItem1);
204 newMenuPopup0.appendChild(newMenuItem2);
205 newMenuPopup0.appendChild(newMenu1);
206 newMenu1.appendChild(newMenuPopup1);
207 newMenuPopup1.appendChild(newMenuItem3);
208 newMenuPopup1.appendChild(newMenuItem4);
209 newMenuPopup1.appendChild(newMenuItem5);
210 //XXX - we have to append the menu to the top-level of the menu bar
211 // only after constructing it. If we append before construction, it is
212 // invalid because it has no children and we don't validate it if we add
214 menuNode.appendChild(newMenu0);
215 menu.forceUpdateNativeMenuAt(
"1|3");
216 // Run basic tests again.
217 ok(runBaseMenuTests(menu),
"base tests #2");
220 var sa =
"Command handler(s) should have activated";
221 var sna =
"Command handler(s) should not have activated";
223 // Test middle items.
224 ok(testItem(menu,
"1|1",
"cmd_NewItem1"),
"#1:" + sa);
225 ok(testItem(menu,
"1|3|1",
"cmd_NewItem4"),
"#2:" + sa);
228 newMenu0.setAttribute(
"hidden",
"true");
229 ok(runBaseMenuTests(menu),
"base tests #3: " + sa); // the base menu should still be unhidden
230 ok(!testItem(menu,
"1|0",
""),
"#3:" + sna);
231 ok(!testItem(menu,
"1|1",
""),
"#4:" + sna);
232 ok(!testItem(menu,
"1|2",
""),
"#5:" + sna);
233 ok(!testItem(menu,
"1|3|0",
""),
"#6:" + sna);
234 ok(!testItem(menu,
"1|3|1",
""),
"#7:" + sna);
235 ok(!testItem(menu,
"1|3|2",
""),
"#8:" + sna);
238 newMenu0.setAttribute(
"hidden",
"false");
239 menu.forceUpdateNativeMenuAt(
"1|3");
240 ok(runBaseMenuTests(menu),
"base tests #4:" + sa);
241 ok(testItem(menu,
"1|0",
"cmd_NewItem0"),
"#9:" + sa);
242 ok(testItem(menu,
"1|1",
"cmd_NewItem1"),
"#10:" + sa);
243 ok(testItem(menu,
"1|2",
"cmd_NewItem2"),
"#11:" + sa);
244 ok(testItem(menu,
"1|3|0",
"cmd_NewItem3"),
"#12:" + sa);
245 ok(testItem(menu,
"1|3|1",
"cmd_NewItem4"),
"#13:" + sa);
246 ok(testItem(menu,
"1|3|2",
"cmd_NewItem5"),
"#14:" + sa);
249 newMenuItem1.setAttribute(
"hidden",
"true");
250 newMenuItem4.setAttribute(
"hidden",
"true");
251 menu.forceUpdateNativeMenuAt(
"1|2");
252 ok(runBaseMenuTests(menu),
"base tests #5:" + sa);
253 ok(testItem(menu,
"1|0",
"cmd_NewItem0"),
"#15:" + sa);
254 ok(testItem(menu,
"1|1",
"cmd_NewItem2"),
"#16:" + sa);
255 ok(!testItem(menu,
"1|2",
""),
"#17:" + sna);
256 ok(testItem(menu,
"1|2|0",
"cmd_NewItem3"),
"#18:" + sa);
257 ok(testItem(menu,
"1|2|1",
"cmd_NewItem5"),
"#19:" + sa);
258 ok(!testItem(menu,
"1|2|2",
""),
"#20:" + sna);
261 newMenuItem1.setAttribute(
"hidden",
"false");
262 newMenuItem4.setAttribute(
"hidden",
"false");
263 //forceUpdateNativeMenuAt(
"1|3");
264 ok(runBaseMenuTests(menu),
"base tests #6:" + sa);
265 ok(testItem(menu,
"1|0",
"cmd_NewItem0"),
"#21:" + sa);
266 ok(testItem(menu,
"1|1",
"cmd_NewItem1"),
"#22:" + sa);
267 ok(testItem(menu,
"1|2",
"cmd_NewItem2"),
"#23:" + sa);
268 ok(testItem(menu,
"1|3|0",
"cmd_NewItem3"),
"#24:" + sa);
269 ok(testItem(menu,
"1|3|1",
"cmd_NewItem4"),
"#25:" + sa);
270 ok(testItem(menu,
"1|3|2",
"cmd_NewItem5"),
"#26:" + sa);
272 // At this point in the tests the state of the menus has been returned
273 // to the originally diagramed state.
276 menuNode.removeChild(newMenu0);
277 ok(runBaseMenuTests(menu),
"base tests #7:" + sa);
278 ok(!testItem(menu,
"1|0",
""),
"#27:" + sna);
279 ok(!testItem(menu,
"1|1",
""),
"#28:" + sna);
280 ok(!testItem(menu,
"1|2",
""),
"#29:" + sna);
281 ok(!testItem(menu,
"1|3|0",
""),
"#30:" + sna);
282 ok(!testItem(menu,
"1|3|1",
""),
"#31:" + sna);
283 ok(!testItem(menu,
"1|3|2",
""),
"#32:" + sna);
284 // return state to original diagramed state
285 menuNode.appendChild(newMenu0);
287 // Test for bug
447042, make sure that adding a menu node with no children
288 // to the menu bar and then adding another menu node with children works.
289 // Menus with no children don't get their native menu items shown and that
290 // caused internal arrays to get out of sync and an append crashed.
291 var tmpMenu0 = createXULMenu(
"tmpMenu0");
292 menuNode.removeChild(newMenu0);
293 menuNode.appendChild(tmpMenu0);
294 menuNode.appendChild(newMenu0);
295 menu.forceUpdateNativeMenuAt(
"1|3");
296 //todo(runBaseMenuTests(menu),
"base tests #8");
297 todo(testItem(menu,
"1|0",
"cmd_NewItem0"),
"#33:" +sa);
298 todo(testItem(menu,
"1|1",
"cmd_NewItem1"),
"#34:" +sa);
299 todo(testItem(menu,
"1|2",
"cmd_NewItem2"),
"#35:" +sa);
300 todo(testItem(menu,
"1|3|0",
"cmd_NewItem3"),
"#36:" +sa);
301 todo(testItem(menu,
"1|3|1",
"cmd_NewItem4"),
"#37:" +sa);
302 todo(testItem(menu,
"1|3|2",
"cmd_NewItem5"),
"#38:" +sa);
303 // return state to original diagramed state
304 menuNode.removeChild(tmpMenu0);
307 // This test is basically a crash test for bug
433858.
308 newMenuItem1.setAttribute(
"hidden",
"true");
309 newMenuItem2.setAttribute(
"hidden",
"true");
310 newMenu1.setAttribute(
"hidden",
"true");
311 menu.forceUpdateNativeMenuAt(
"1");
312 newMenuItem1.setAttribute(
"hidden",
"false");
313 newMenuItem2.setAttribute(
"hidden",
"false");
314 newMenu1.setAttribute(
"hidden",
"false");
315 menu.forceUpdateNativeMenuAt(
"1");
317 // Run tests where the menu nodes are not in the document's node tree.
318 runDetachedMenuTests(false);
319 runDetachedMenuTests(true);
322 ok(false,
"Caught an exception: " + e);
328 setTimeout(_delayedOnLoad,
1000);