Bug 1861709 replace AudioCallbackDriver::ThreadRunning() assertions that mean to...
[gecko.git] / widget / tests / standalone_native_menu_window.xhtml
blob4155126ad5556e2e8db064afb2f89b7d72f0488c
1 <?xml version="1.0"?>
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"
7 width="300"
8 height="300"
9 onload="onLoad();"
10 title="nsIStandaloneNativeMenu Test">
12 <command id="cmd_FooItem0" oncommand="gExecutedCommandID = 'cmd_FooItem0';"/>
13 <command id="cmd_FooItem1" oncommand="gExecutedCommandID = 'cmd_FooItem1';"/>
14 <command id="cmd_BarItem0" oncommand="gExecutedCommandID = 'cmd_BarItem0';"/>
15 <command id="cmd_BarItem1" oncommand="gExecutedCommandID = 'cmd_BarItem1';"/>
16 <command id="cmd_NewItem0" oncommand="gExecutedCommandID = 'cmd_NewItem0';"/>
17 <command id="cmd_NewItem1" oncommand="gExecutedCommandID = 'cmd_NewItem1';"/>
18 <command id="cmd_NewItem2" oncommand="gExecutedCommandID = 'cmd_NewItem2';"/>
19 <command id="cmd_NewItem3" oncommand="gExecutedCommandID = 'cmd_NewItem3';"/>
20 <command id="cmd_NewItem4" oncommand="gExecutedCommandID = 'cmd_NewItem4';"/>
21 <command id="cmd_NewItem5" oncommand="gExecutedCommandID = '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
26 children. -->
27 <popupset>
28 <menupopup id="standalonenativemenu">
29 <menu id="foo" label="Foo">
30 <menupopup>
31 <menuitem label="FooItem0" command="cmd_FooItem0"/>
32 <menuitem label="FooItem1" command="cmd_FooItem1"/>
33 <menuseparator/>
34 <menu label="Bar">
35 <menupopup>
36 <menuitem label="BarItem0" command="cmd_BarItem0"/>
37 <menuitem label="BarItem1" command="cmd_BarItem1"/>
38 </menupopup>
39 </menu>
40 </menupopup>
41 </menu>
42 </menupopup>
43 </popupset>
45 <script type="application/javascript"><![CDATA[
47 function ok(condition, message) {
48 window.arguments[0].SimpleTest.ok(condition, message);
51 function is(a, b, message) {
52 window.arguments[0].SimpleTest.is(a, b, message);
55 function isnot(a, b, message) {
56 window.arguments[0].SimpleTest.isnot(a, b, message);
59 function todo(condition, message) {
60 window.arguments[0].SimpleTest.todo(condition, message);
63 function todo_is(a, b, message) {
64 window.arguments[0].SimpleTest.todo_is(a, b, message);
67 function todo_isnot(a, b, message) {
68 window.arguments[0].SimpleTest.todo_isnot(a, b, message);
71 function onTestsFinished() {
72 window.close();
73 window.arguments[0].SimpleTest.finish();
76 var gExecutedCommandID;
78 // returns the executed command ID, or the empty string if nothing was executed
79 function activateItem(menu, location) {
80 try {
81 gExecutedCommandID = "";
82 menu.menuWillOpen();
83 menu.activateNativeMenuItemAt(location);
84 return gExecutedCommandID;
86 catch (e) {
87 // activateNativeMenuItemAt throws an exception if the item was not found
88 dump(e + "\n");
89 return "";
93 function testItem(menu, location, targetID) {
94 var activatedCommandID = activateItem(menu, location);
95 return activatedCommandID != "" && activatedCommandID == targetID;
98 var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
100 function createXULMenuPopup() {
101 return document.createElementNS(XUL_NS, "menupopup");
104 function createXULMenu(aLabel) {
105 var item = document.createElementNS(XUL_NS, "menu");
106 item.setAttribute("label", aLabel);
107 return item;
110 function createXULMenuItem(aLabel, aCommandId) {
111 var item = document.createElementNS(XUL_NS, "menuitem");
112 item.setAttribute("label", aLabel);
113 item.setAttribute("command", aCommandId);
114 return item;
117 function runBaseMenuTests(menu) {
118 menu.forceUpdateNativeMenuAt("0|3");
119 return testItem(menu, "0|0", "cmd_FooItem0") &&
120 testItem(menu, "0|1", "cmd_FooItem1") &&
121 testItem(menu, "0|3|0", "cmd_BarItem0") &&
122 testItem(menu, "0|3|1", "cmd_BarItem1");
125 function createStandaloneNativeMenu(menuNode) {
126 try {
127 let menu = Cc["@mozilla.org/widget/standalonenativemenu;1"].createInstance(Ci.nsIStandaloneNativeMenu);
128 menu.init(menuNode);
129 return menu;
130 } catch (e) {
131 ok(false, "Failed creating nsIStandaloneNativeMenu instance");
132 throw e;
136 function runDetachedMenuTests(addMenupopupBeforeCreatingSNM) {
137 let menu = createXULMenu("Detached menu");
138 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>');
139 let menupopup = createXULMenuPopup();
141 let popupShowingFired = false;
142 let itemActivated = false;
144 menupopup.addEventListener("popupshowing", function (e) {
145 popupShowingFired = true;
147 let menuitem = document.createElementNS(XUL_NS, "menuitem");
148 menuitem.setAttribute("label", "detached menu item");
149 /* eslint-disable-next-line no-shadow */
150 menuitem.addEventListener("command", function (e) {
151 itemActivated = true;
153 menupopup.appendChild(menuitem);
156 // It shouldn't make a difference whether the menupopup is added to the
157 // menu element before or after we create the nsIStandaloneNativeMenu
158 // instance with it. We test both orders by calling this function twice
159 // with different values for addMenupopupBeforeCreatingSNM.
161 var menuSNM = null; // the nsIStandaloneNativeMenu object for "menu"
162 if (addMenupopupBeforeCreatingSNM) {
163 menu.appendChild(menupopup);
164 menuSNM = createStandaloneNativeMenu(menu);
165 } else {
166 menuSNM = createStandaloneNativeMenu(menu);
167 menu.appendChild(menupopup);
170 try {
171 ok(!popupShowingFired, "popupshowing shouldn't have fired before our call to menuWillOpen()");
172 menuSNM.menuWillOpen();
173 ok(popupShowingFired, "calling menuWillOpen() should have notified our popupshowing listener");
175 ok(!itemActivated, "our dynamically-added menuitem shouldn't have been activated yet");
176 menuSNM.activateNativeMenuItemAt("0");
177 ok(itemActivated, "the new menu item should have been activated now");
178 } catch (ex) {
179 ok(false, "dynamic menu test failed: " + ex);
183 function onLoad() {
184 var _delayedOnLoad = function() {
185 try {
187 var menuNode = document.getElementById("standalonenativemenu");
188 var menu = createStandaloneNativeMenu(menuNode);
190 // First let's run the base menu tests.
191 ok(runBaseMenuTests(menu), "base tests #1");
193 // Set up some nodes that we'll use.
194 var newMenu0 = createXULMenu("NewMenu0");
195 var newMenu1 = createXULMenu("NewMenu1");
196 var newMenuPopup0 = createXULMenuPopup();
197 var newMenuPopup1 = createXULMenuPopup();
198 var newMenuItem0 = createXULMenuItem("NewMenuItem0", "cmd_NewItem0");
199 var newMenuItem1 = createXULMenuItem("NewMenuItem1", "cmd_NewItem1");
200 var newMenuItem2 = createXULMenuItem("NewMenuItem2", "cmd_NewItem2");
201 var newMenuItem3 = createXULMenuItem("NewMenuItem3", "cmd_NewItem3");
202 var newMenuItem4 = createXULMenuItem("NewMenuItem4", "cmd_NewItem4");
203 var newMenuItem5 = createXULMenuItem("NewMenuItem5", "cmd_NewItem5");
205 // Create another submenu with hierarchy via DOM manipulation.
206 // ******************
207 // * Foo * NewMenu0 * <- Menu bar
208 // ******************
209 // ****************
210 // * NewMenuItem0 * <- NewMenu0 submenu
211 // ****************
212 // * NewMenuItem1 *
213 // ****************
214 // * NewMenuItem2 *
215 // *******************************
216 // * NewMenu1 > * NewMenuItem3 * <- NewMenu1 submenu
217 // *******************************
218 // * NewMenuItem4 *
219 // ****************
220 // * NewMenuItem5 *
221 // ****************
222 newMenu0.appendChild(newMenuPopup0);
223 newMenuPopup0.appendChild(newMenuItem0);
224 newMenuPopup0.appendChild(newMenuItem1);
225 newMenuPopup0.appendChild(newMenuItem2);
226 newMenuPopup0.appendChild(newMenu1);
227 newMenu1.appendChild(newMenuPopup1);
228 newMenuPopup1.appendChild(newMenuItem3);
229 newMenuPopup1.appendChild(newMenuItem4);
230 newMenuPopup1.appendChild(newMenuItem5);
231 //XXX - we have to append the menu to the top-level of the menu bar
232 // only after constructing it. If we append before construction, it is
233 // invalid because it has no children and we don't validate it if we add
234 // children later.
235 menuNode.appendChild(newMenu0);
236 menu.forceUpdateNativeMenuAt("1|3");
237 // Run basic tests again.
238 ok(runBaseMenuTests(menu), "base tests #2");
240 // Error strings.
241 var sa = "Command handler(s) should have activated";
242 var sna = "Command handler(s) should not have activated";
244 // Test middle items.
245 is(activateItem(menu, "1|1"), "cmd_NewItem1", "#1:" + sa);
246 is(activateItem(menu, "1|3|1"), "cmd_NewItem4", "#2:" + sa);
248 // Hide newMenu0.
249 newMenu0.setAttribute("hidden", "true");
250 ok(runBaseMenuTests(menu), "base tests #3: " + sa); // the base menu should still be unhidden
251 is(activateItem(menu, "1|0"), "", "#3:" + sna);
252 is(activateItem(menu, "1|1"), "", "#4:" + sna);
253 is(activateItem(menu, "1|2"), "", "#5:" + sna);
254 is(activateItem(menu, "1|3|0"), "", "#6:" + sna);
255 is(activateItem(menu, "1|3|1"), "", "#7:" + sna);
256 is(activateItem(menu, "1|3|2"), "", "#8:" + sna);
258 // Show newMenu0.
259 newMenu0.setAttribute("hidden", "false");
260 menu.forceUpdateNativeMenuAt("1|3");
261 ok(runBaseMenuTests(menu), "base tests #4:" + sa);
262 is(activateItem(menu, "1|0"), "cmd_NewItem0", "#9:" + sa);
263 is(activateItem(menu, "1|1"), "cmd_NewItem1", "#10:" + sa);
264 is(activateItem(menu, "1|2"), "cmd_NewItem2", "#11:" + sa);
265 is(activateItem(menu, "1|3|0"), "cmd_NewItem3", "#12:" + sa);
266 is(activateItem(menu, "1|3|1"), "cmd_NewItem4", "#13:" + sa);
267 is(activateItem(menu, "1|3|2"), "cmd_NewItem5", "#14:" + sa);
269 // Hide items.
270 newMenuItem1.setAttribute("hidden", "true");
271 newMenuItem4.setAttribute("hidden", "true");
272 menu.forceUpdateNativeMenuAt("1|2");
273 ok(runBaseMenuTests(menu), "base tests #5:" + sa);
274 is(activateItem(menu, "1|0"), "cmd_NewItem0", "#15:" + sa);
275 is(activateItem(menu, "1|1"), "cmd_NewItem2", "#16:" + sa);
276 is(activateItem(menu, "1|2"), "", "#17:" + sna);
277 is(activateItem(menu, "1|2|0"), "cmd_NewItem3", "#18:" + sa);
278 is(activateItem(menu, "1|2|1"), "cmd_NewItem5", "#19:" + sa);
279 is(activateItem(menu, "1|2|2"), "", "#20:" + sna);
281 // Show items.
282 newMenuItem1.setAttribute("hidden", "false");
283 newMenuItem4.setAttribute("hidden", "false");
284 //forceUpdateNativeMenuAt("1|3");
285 ok(runBaseMenuTests(menu), "base tests #6:" + sa);
286 is(activateItem(menu, "1|0"), "cmd_NewItem0", "#21:" + sa);
287 is(activateItem(menu, "1|1"), "cmd_NewItem1", "#22:" + sa);
288 is(activateItem(menu, "1|2"), "cmd_NewItem2", "#23:" + sa);
289 is(activateItem(menu, "1|3|0"), "cmd_NewItem3", "#24:" + sa);
290 is(activateItem(menu, "1|3|1"), "cmd_NewItem4", "#25:" + sa);
291 is(activateItem(menu, "1|3|2"), "cmd_NewItem5", "#26:" + sa);
293 // At this point in the tests the state of the menus has been returned
294 // to the originally diagramed state.
296 // Remove menu.
297 menuNode.removeChild(newMenu0);
298 ok(runBaseMenuTests(menu), "base tests #7:" + sa);
299 is(activateItem(menu, "1|0"), "", "#27:" + sna);
300 is(activateItem(menu, "1|1"), "", "#28:" + sna);
301 is(activateItem(menu, "1|2"), "", "#29:" + sna);
302 is(activateItem(menu, "1|3|0"), "", "#30:" + sna);
303 is(activateItem(menu, "1|3|1"), "", "#31:" + sna);
304 is(activateItem(menu, "1|3|2"), "", "#32:" + sna);
305 // return state to original diagramed state
306 menuNode.appendChild(newMenu0);
308 // The following is based on a similar test bug 447042 from the native
309 // menu bar test: Make sure that adding a menu node with no children
310 // to the menu bar and then adding another menu node with children works.
311 // In the menubar, root menus with no children are skipped - they're not
312 // visible in the menubar.
313 // Regular menus currently treat submenus without children differently:
314 // submenus without children *are* visible.
315 // We may want to change this in the future.
316 // After the mutation below we have the following root menu content:
317 // - [0] Foo (with submenu)
318 // - [1] tmpMenu0 (with empty submenu)
319 // - [2] NewMenu0 (with submenu)
320 // Since the empty tmpMenu0 item is not skipped, NewMenu0 has index 2,
321 // so we use "2|..." below, rather than the "1|..." that's used in the
322 // menubar test.
323 var tmpMenu0 = createXULMenu("tmpMenu0");
324 menuNode.removeChild(newMenu0);
325 menuNode.appendChild(tmpMenu0);
326 menuNode.appendChild(newMenu0);
327 menu.forceUpdateNativeMenuAt("2|3");
328 ok(runBaseMenuTests(menu), "base tests #8");
329 is(activateItem(menu, "2|0"), "cmd_NewItem0", "#33:" + sa);
330 is(activateItem(menu, "2|1"), "cmd_NewItem1", "#34:" + sa);
331 is(activateItem(menu, "2|2"), "cmd_NewItem2", "#35:" + sa);
332 is(activateItem(menu, "2|3|0"), "cmd_NewItem3", "#36:" + sa);
333 is(activateItem(menu, "2|3|1"), "cmd_NewItem4", "#37:" + sa);
334 is(activateItem(menu, "2|3|2"), "cmd_NewItem5", "#38:" + sa);
335 // return state to original diagramed state
336 menuNode.removeChild(tmpMenu0);
338 // This test is basically a crash test for bug 433858.
339 newMenuItem1.setAttribute("hidden", "true");
340 newMenuItem2.setAttribute("hidden", "true");
341 newMenu1.setAttribute("hidden", "true");
342 menu.forceUpdateNativeMenuAt("1");
343 newMenuItem1.setAttribute("hidden", "false");
344 newMenuItem2.setAttribute("hidden", "false");
345 newMenu1.setAttribute("hidden", "false");
346 menu.forceUpdateNativeMenuAt("1");
348 // Check that "path components" which are out-of-range are not ignored.
349 // There are only two menu items in the root menu (with index 0 and 1),
350 // so index 2 is out of range.
351 is(activateItem(menu, "2|1|0"), "", "#39:" + sna);
353 // Check that hiding and then un-hiding the root menu doesn't result in
354 // a cyclic native menu structure.
355 menuNode.setAttribute("collapsed", "true");
356 menuNode.removeAttribute("collapsed");
357 ok(runBaseMenuTests(menu), "base tests #9");
359 // Run tests where the menu nodes are not in the document's node tree.
360 runDetachedMenuTests(false);
361 runDetachedMenuTests(true);
363 } catch (e) {
364 ok(false, "Caught an exception: " + e);
365 } finally {
366 onTestsFinished();
370 setTimeout(_delayedOnLoad, 1000);
373 ]]></script>
374 </window>