diff --git a/toolkit/content/tests/chrome/Makefile.in b/toolkit/content/tests/chrome/Makefile.in index 4f7eb7297ca..f5dc3514dee 100644 --- a/toolkit/content/tests/chrome/Makefile.in +++ b/toolkit/content/tests/chrome/Makefile.in @@ -54,6 +54,8 @@ _TEST_FILES = bug288254_window.xul \ test_bug366992.xul \ bug331215_window.xul \ test_bug331215.xul \ + test_popup_preventdefault_chrome.xul \ + window_popup_preventdefault_chrome.xul \ $(NULL) libs:: $(_TEST_FILES) diff --git a/toolkit/content/tests/chrome/test_popup_preventdefault_chrome.xul b/toolkit/content/tests/chrome/test_popup_preventdefault_chrome.xul new file mode 100644 index 00000000000..b96b67a73ad --- /dev/null +++ b/toolkit/content/tests/chrome/test_popup_preventdefault_chrome.xul @@ -0,0 +1,33 @@ + + + + + + + Popup Attribute Tests + + + +

+

+ +
+
+ + +
diff --git a/toolkit/content/tests/chrome/window_popup_preventdefault_chrome.xul b/toolkit/content/tests/chrome/window_popup_preventdefault_chrome.xul new file mode 100644 index 00000000000..8c1cd650986 --- /dev/null +++ b/toolkit/content/tests/chrome/window_popup_preventdefault_chrome.xul @@ -0,0 +1,75 @@ + + + + + + Popup Prevent Default Tests + + + + + + + + + diff --git a/toolkit/content/tests/widgets/Makefile.in b/toolkit/content/tests/widgets/Makefile.in index b341961ca3b..82d70af37c2 100644 --- a/toolkit/content/tests/widgets/Makefile.in +++ b/toolkit/content/tests/widgets/Makefile.in @@ -51,6 +51,17 @@ _TEST_FILES = test_bug360220.xul \ test_menulist_keynav.xul \ test_popup_coords.xul \ test_popup_recreate.xul \ + test_popup_button.xul \ + test_menuchecks.xul \ + test_popup_attribute.xul \ + test_popup_preventdefault.xul \ + test_tooltip.xul \ + popup_shared.js \ + popup_trigger.js \ + window_popup_button.xul \ + window_menuchecks.xul \ + window_popup_attribute.xul \ + window_tooltip.xul \ test_progressmeter.xul \ # Disabled until we can figure out why they're causing failures on the Windows # unit test box (bug 389616) @@ -58,5 +69,10 @@ _TEST_FILES = test_bug360220.xul \ # test_timepicker.xul \ $(NULL) +ifeq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) +_TEST_FILES += test_menubar.xul \ + window_menubar.xul +endif + libs:: $(_TEST_FILES) $(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir) diff --git a/toolkit/content/tests/widgets/popup_shared.js b/toolkit/content/tests/widgets/popup_shared.js new file mode 100644 index 00000000000..299367bd11e --- /dev/null +++ b/toolkit/content/tests/widgets/popup_shared.js @@ -0,0 +1,296 @@ +/* + * This script is used for menu and popup tests. Call startPopupTests to start + * the tests, passing an array of tests as an argument. Each test is an object + * with the following properties: + * testname - name of the test + * test - function to call to perform the test + * events - a list of events that are expected to be fired in sequence + * as a result of calling the 'test' function. This list should be + * an array of strings of the form "eventtype targetid" where + * 'eventtype' is the event type and 'targetid' is the id of + * target of the event. This function will be passed two + * arguments, the testname and the step argument. + * Alternatively, events may be a function which returns the array + * of events. This can be used when the events vary per platform. + * result - function to call after all the events have fired to check + * for additional results. May be null. This function will be + * passed two arguments, the testname and the step argument. + * steps - optional array of values. The test will be repeated for + * each step, passing each successive value within the array to + * the test and result functions + * autohide - if set, should be set to the id of a popup to hide after + * the test is complete. This is a convenience for some tests. + * condition - an optional function which, if it returns false, causes the + * test to be skipped. + * end - used for debugging. Set to true to stop the tests after running + * this one. + */ + +const menuactiveAttribute = "_moz-menuactive"; + +var gPopupTests = null; +var gTestIndex = -1; +var gTestStepIndex = 0; +var gTestEventIndex = 0; +var gAutoHide = false; +var gExpectedEventDetails = null; + +function startPopupTests(tests) +{ + document.addEventListener("popupshowing", eventOccured, false); + document.addEventListener("popupshown", eventOccured, false); + document.addEventListener("popuphiding", eventOccured, false); + document.addEventListener("popuphidden", eventOccured, false); + document.addEventListener("command", eventOccured, false); + document.addEventListener("DOMMenuItemActive", eventOccured, false); + document.addEventListener("DOMMenuItemInactive", eventOccured, false); + document.addEventListener("DOMMenuInactive", eventOccured, false); + document.addEventListener("DOMMenuBarActive", eventOccured, false); + document.addEventListener("DOMMenuBarInactive", eventOccured, false); + + gPopupTests = tests; + + goNext(); +} + +function finish() +{ + window.close(); + window.opener.SimpleTest.finish(); +} + +function ok(condition, message) { + window.opener.SimpleTest.ok(condition, message); +} + +function is(left, right, message) { + window.opener.SimpleTest.is(left, right, message); +} + +function eventOccured(event) +{ + if (gPopupTests.length <= gTestIndex) { + ok(false, "Extra " + event.type + " event fired"); + return; + } + + var test = gPopupTests[gTestIndex]; + if ("autohide" in test && gAutoHide) { + if (event.type == "DOMMenuInactive") { + gAutoHide = false; + setTimeout(goNextStep, 0); + } + return; + } + + var events = test.events; + if (typeof events == "function") + events = events(); + if (events) { + if (events.length <= gTestEventIndex) { + ok(false, "Extra " + event.type + " event fired " + gPopupTests[gTestIndex].testname); + return; + } + + var eventitem = events[gTestEventIndex].split(" "); + var matches = (eventitem[1] == "#tooltip") ? + (event.originalTarget.localName == "tooltip" && + event.originalTarget.getAttribute("default") == "true") : + (eventitem[0] == event.type && eventitem[1] == event.target.id); + ok(matches, test.testname + " " + event.type + " fired"); + + if (matches) { + gTestEventIndex++ + if (events.length <= gTestEventIndex) + setTimeout(checkResult, 0); + } + } +} + +function checkResult() +{ + var step = null; + var test = gPopupTests[gTestIndex]; + if ("steps" in test) + step = test.steps[gTestStepIndex]; + + if ("result" in test) + test.result(test.testname, step); + + if ("autohide" in test) { + gAutoHide = true; + document.getElementById(test.autohide).hidePopup(); + return; + } + + goNextStep(); +} + +function goNextStep() +{ + gTestEventIndex = 0; + + var step = null; + var test = gPopupTests[gTestIndex]; + if ("steps" in test) { + gTestStepIndex++; + step = test.steps[gTestStepIndex]; + if (gTestStepIndex < test.steps.length) { + test.test(test.testname, step); + return; + } + } + + goNext(); +} + +function goNext() +{ + if (gTestIndex >= 0 && "end" in gPopupTests[gTestIndex] && gPopupTests[gTestIndex].end) { + finish(); + return; + } + + gTestIndex++; + gTestStepIndex = 0; + if (gTestIndex < gPopupTests.length) { + var test = gPopupTests[gTestIndex] + + // skip the test if the condition returns false + if ("condition" in test && !test.condition()) { + goNext(); + return; + } + + // start with the first step if there are any + var step = null; + if ("steps" in test) + step = test.steps[gTestStepIndex]; + + test.test(test.testname, step); + + // no events to check for so just check the result + if (!("events" in test)) + checkResult(); + } + else { + finish(); + } +} + +function openMenu(menu) +{ + if ("open" in menu) { + menu.open = true; + } + else { + var bo = menu.boxObject; + if (bo instanceof Components.interfaces.nsIMenuBoxObject) + bo.openMenu(true); + else + synthesizeMouse(menu, 4, 4, { }); + } +} + +function closeMenu(menu, popup) +{ + if ("open" in menu) { + menu.open = false; + } + else { + var bo = menu.boxObject; + if (bo instanceof Components.interfaces.nsIMenuBoxObject) + bo.openMenu(false); + else + popup.hidePopup(); + } +} + +function checkActive(popup, id, testname) +{ + var activeok = true; + var children = popup.childNodes; + for (var c = 0; c < children.length; c++) { + var child = children[c]; + if ((id == child.id && child.getAttribute(menuactiveAttribute) != "true") || + (id != child.id && child.hasAttribute(menuactiveAttribute) != "")) { + activeok = false; + break; + } + } + ok(activeok, testname + " item " + (id ? id : "none") + " active"); +} + +function checkOpen(menuid, testname) +{ + var menu = document.getElementById(menuid); + if ("open" in menu) + ok(menu.open, testname + " " + menuid + " menu is open"); + else if (menu.boxObject instanceof Components.interfaces.nsIMenuBoxObject) + ok(menu.getAttribute("open") == "true", testname + " " + menuid + " menu is open"); +} + +function checkClosed(menuid, testname) +{ + var menu = document.getElementById(menuid); + if ("open" in menu) + ok(!menu.open, testname + " " + menuid + " menu is open"); + else if (menu.boxObject instanceof Components.interfaces.nsIMenuBoxObject) + ok(!menu.hasAttribute("open"), testname + " " + menuid + " menu is closed"); +} + +function convertPosition(anchor, align) +{ + if (anchor == "topleft" && align == "topleft") return "overlap"; + if (anchor == "topleft" && align == "topright") return "start_before"; + if (anchor == "topleft" && align == "bottomleft") return "before_start"; + if (anchor == "topright" && align == "topleft") return "end_before"; + if (anchor == "topright" && align == "bottomright") return "before_end"; + if (anchor == "bottomleft" && align == "bottomright") return "start_after"; + if (anchor == "bottomleft" && align == "topleft") return "after_start"; + if (anchor == "bottomright" && align == "bottomleft") return "end_after"; + if (anchor == "bottomright" && align == "topright") return "after_end"; + return ""; +} + +function compareEdge(anchor, popup, edge, offsetX, offsetY, testname) +{ + testname += " " + edge; + + checkOpen(anchor.id, testname); + + var anchorrect = anchor.getBoundingClientRect(); + var popuprect = popup.getBoundingClientRect(); + var check1 = false, check2 = false; + + ok((Math.round(popuprect.right) - Math.round(popuprect.left)) && + (Math.round(popuprect.bottom) - Math.round(popuprect.top)), + testname + " size"); + + if (edge == "overlap") { + ok(Math.round(anchorrect.left) + offsetY == Math.round(popuprect.left) && + Math.round(anchorrect.top) + offsetY == Math.round(popuprect.top), + testname + " position"); + return; + } + + if (edge.indexOf("before") == 0) + check1 = (Math.round(anchorrect.top) + offsetY == Math.round(popuprect.bottom)); + else if (edge.indexOf("after") == 0) + check1 = (Math.round(anchorrect.bottom) + offsetY == Math.round(popuprect.top)); + else if (edge.indexOf("start") == 0) + check1 = (Math.round(anchorrect.left) + offsetX == Math.round(popuprect.right)); + else if (edge.indexOf("end") == 0) + check1 = (Math.round(anchorrect.right) + offsetX == Math.round(popuprect.left)); + + if (0 < edge.indexOf("before")) + check2 = (Math.round(anchorrect.top) + offsetY == Math.round(popuprect.top)); + else if (0 < edge.indexOf("after")) + check2 = (Math.round(anchorrect.bottom) + offsetY == Math.round(popuprect.bottom)); + else if (0 < edge.indexOf("start")) + check2 = (Math.round(anchorrect.left) + offsetX == Math.round(popuprect.left)); + else if (0 < edge.indexOf("end")) + check2 = (Math.round(anchorrect.right) + offsetX == Math.round(popuprect.right)); + + ok(check1 && check2, testname + " position"); +} diff --git a/toolkit/content/tests/widgets/popup_trigger.js b/toolkit/content/tests/widgets/popup_trigger.js new file mode 100644 index 00000000000..322565378b5 --- /dev/null +++ b/toolkit/content/tests/widgets/popup_trigger.js @@ -0,0 +1,631 @@ +var gMenuPopup = null; +var gTrigger = null; +var gIsMenu = false; +var gScreenX = -1, gScreenY = -1; + +function runTests() +{ + gMenuPopup = document.getElementById("thepopup"); + gTrigger = document.getElementById("trigger"); + + gIsMenu = gTrigger.boxObject instanceof Components.interfaces.nsIMenuBoxObject; + + var mouseFn = function(event) { + gScreenX = event.screenX; + gScreenY = event.screenY; + } + + // a hacky way to get the screen position of the document + window.addEventListener("mousedown", mouseFn, false); + synthesizeMouse(document.documentElement, 0, 0, { }); + window.removeEventListener("mousedown", mouseFn, false); + startPopupTests(popupTests); +} + +var popupTests = [ +{ + testname: "mouse click on trigger", + events: [ "popupshowing thepopup", "popupshown thepopup" ], + test: function() { synthesizeMouse(gTrigger, 4, 4, { }); }, + result: function (testname) { + checkActive(gMenuPopup, "", testname); + checkOpen("trigger", testname); + // if a menu, the popup should be opened underneath the menu in the + // 'after_start' position, otherwise it is opened at the mouse position + if (gIsMenu) + compareEdge(gTrigger, gMenuPopup, "after_start", 0, 0, testname); + } +}, +{ + // check that pressing cursor down while there is no selection + // highlights the first item + testname: "cursor down no selection", + events: [ "DOMMenuItemActive item1" ], + test: function() { synthesizeKey("VK_DOWN", { }); }, + result: function(testname) { checkActive(gMenuPopup, "item1", testname); } +}, +{ + // check that pressing cursor up wraps and highlights the last item + testname: "cursor up wrap", + events: [ "DOMMenuItemInactive item1", "DOMMenuItemActive last" ], + test: function() { synthesizeKey("VK_UP", { }); }, + result: function(testname) { + checkActive(gMenuPopup, "last", testname); + } +}, +{ + // check that pressing cursor down wraps and highlights the first item + testname: "cursor down wrap", + events: [ "DOMMenuItemInactive last", "DOMMenuItemActive item1" ], + test: function() { synthesizeKey("VK_DOWN", { }); }, + result: function(testname) { checkActive(gMenuPopup, "item1", testname); } +}, +{ + // check that pressing cursor down highlights the second item + testname: "cursor down", + events: [ "DOMMenuItemInactive item1", "DOMMenuItemActive item2" ], + test: function() { synthesizeKey("VK_DOWN", { }); }, + result: function(testname) { checkActive(gMenuPopup, "item2", testname); } +}, +{ + // check that pressing cursor up highlights the second item + testname: "cursor up", + events: [ "DOMMenuItemInactive item2", "DOMMenuItemActive item1" ], + test: function() { synthesizeKey("VK_UP", { }); }, + result: function(testname) { checkActive(gMenuPopup, "item1", testname); } +}, +{ + // cursor left should not do anything + testname: "cursor left", + test: function() { synthesizeKey("VK_LEFT", { }); }, + result: function(testname) { checkActive(gMenuPopup, "item1", testname); } +}, +{ + // cursor right should not do anything + testname: "cursor right", + test: function() { synthesizeKey("VK_RIGHT", { }); }, + result: function(testname) { checkActive(gMenuPopup, "item1", testname); } +}, +{ + // check cursor down when a disabled item exists in the menu + testname: "cursor down disabled", + events: function() { + // On Windows, disabled items are included when navigating, but on + // other platforms, disabled items are skipped over + if (navigator.platform.indexOf("Win") == 0) + return [ "DOMMenuItemInactive item1", "DOMMenuItemActive item2" ]; + else + return [ "DOMMenuItemInactive item1", "DOMMenuItemActive amenu" ]; + }, + test: function() { + document.getElementById("item2").disabled = true; + synthesizeKey("VK_DOWN", { }); + } +}, +{ + // check cursor up when a disabled item exists in the menu + testname: "cursor up disabled", + events: function() { + if (navigator.platform.indexOf("Win") == 0) + return [ "DOMMenuItemInactive item2", "DOMMenuItemActive amenu", + "DOMMenuItemInactive amenu", "DOMMenuItemActive item2", + "DOMMenuItemInactive item2", "DOMMenuItemActive item1" ]; + else + return [ "DOMMenuItemInactive amenu", "DOMMenuItemActive item1" ]; + }, + test: function() { + if (navigator.platform.indexOf("Win") == 0) + synthesizeKey("VK_DOWN", { }); + synthesizeKey("VK_UP", { }); + if (navigator.platform.indexOf("Win") == 0) + synthesizeKey("VK_UP", { }); + } +}, +{ + testname: "mouse click outside", + events: [ "popuphiding thepopup", "popuphidden thepopup", + "DOMMenuItemInactive item1", "DOMMenuInactive thepopup" ], + test: function() { + gMenuPopup.hidePopup(); + // XXXndeakin event simulation fires events outside of the platform specific + // widget code so the popup capturing isn't handled. Thus, the menu won't + // rollup this way. + // synthesizeMouse(gTrigger, 0, -12, { }); + }, + result: function(testname, step) { checkClosed("trigger", testname); } +}, +{ + // these tests check to ensure that passing an anchor and position + // puts the popup in the right place + testname: "open popup anchored", + events: [ "popupshowing thepopup", "popupshown thepopup" ], + autohide: "thepopup", + steps: ["before_start", "before_end", "after_start", "after_end", + "start_before", "start_after", "end_before", "end_after", "overlap"], + test: function(testname, step) { gMenuPopup.openPopup(gTrigger, step, 0, 0, false, false); }, + result: function(testname, step) { compareEdge(gTrigger, gMenuPopup, step, 0, 0, testname); } +}, +{ + // these tests check to ensure that the position attribute can be used + // to set the position of a popup instead of passing it as an argument + testname: "open popup anchored with attribute", + events: [ "popupshowing thepopup", "popupshown thepopup" ], + autohide: "thepopup", + steps: ["before_start", "before_end", "after_start", "after_end", + "start_before", "start_after", "end_before", "end_after", "overlap"], + test: function(testname, step) { + gMenuPopup.setAttribute("position", step); + gMenuPopup.openPopup(gTrigger, "", 0, 0, false, false); + }, + result: function(testname, step) { compareEdge(gTrigger, gMenuPopup, step, 0, 0, testname); } +}, +{ + // this test checks to ensure that attributes override flag to openPopup + // can be used to override the popup's position + testname: "open popup anchored with override", + events: [ "popupshowing thepopup", "popupshown thepopup" ], + test: function(testname, step) { + // attribute overrides the position passed in + gMenuPopup.setAttribute("position", "end_after"); + gMenuPopup.openPopup(gTrigger, "before_start", 0, 0, false, true); + }, + result: function(testname, step) { compareEdge(gTrigger, gMenuPopup, "end_after", 0, 0, testname); } +}, +{ + testname: "close popup with escape", + events: [ "popuphiding thepopup", "popuphidden thepopup", + "DOMMenuInactive thepopup", ], + test: function(testname, step) { + synthesizeKey("VK_ESCAPE", { }); + checkClosed("trigger", testname); + } +}, +{ + // check that offsets may be supplied to the openPopup method + testname: "open popup anchored with offsets", + events: [ "popupshowing thepopup", "popupshown thepopup" ], + autohide: "thepopup", + test: function(testname, step) { + // attribute is empty so does not override + gMenuPopup.setAttribute("position", ""); + gMenuPopup.openPopup(gTrigger, "before_start", 5, 10, true, true); + }, + result: function(testname, step) { compareEdge(gTrigger, gMenuPopup, "before_start", 5, 10, testname); } +}, +{ + // these tests check to ensure that passing an anchor and position + // puts the popup in the right place + testname: "show popup anchored", + condition: function() { + // only perform this test for popups not in a menu, such as those using + // the popup attribute, as the showPopup implementation in popup.xml + // calls openMenu if the popup is inside a menu + return !gIsMenu; + }, + events: [ "popupshowing thepopup", "popupshown thepopup" ], + autohide: "thepopup", + steps: [["topleft", "topleft"], + ["topleft", "topright"], ["topleft", "bottomleft"], + ["topright", "topleft"], ["topright", "bottomright"], + ["bottomleft", "bottomright"], ["bottomleft", "topleft"], + ["bottomright", "bottomleft"], ["bottomright", "topright"]], + test: function(testname, step) { + // the attributes should be ignored + gMenuPopup.setAttribute("popupanchor", "topright"); + gMenuPopup.setAttribute("popupalign", "bottomright"); + gMenuPopup.setAttribute("position", "end_after"); + gMenuPopup.showPopup(gTrigger, -1, -1, "popup", step[0], step[1]); + }, + result: function(testname, step) { + var pos = convertPosition(step[0], step[1]); + compareEdge(gTrigger, gMenuPopup, pos, 0, 0, testname); + gMenuPopup.removeAttribute("popupanchor"); + gMenuPopup.removeAttribute("popupalign"); + gMenuPopup.removeAttribute("position"); + } +}, +{ + testname: "show popup with position", + condition: function() { return !gIsMenu; }, + events: [ "popupshowing thepopup", "popupshown thepopup" ], + autohide: "thepopup", + test: function(testname, step) { + gMenuPopup.showPopup(gTrigger, gScreenX + 60, gScreenY + 15, + "context", "topleft", "bottomright"); + }, + result: function(testname, step) { + var rect = gMenuPopup.getBoundingClientRect(); + ok(rect.left == 60 && rect.top == 15 && rect.right && rect.bottom, testname); + } +}, +{ + // if no anchor is supplied to openPopup, it should be opened relative + // to the viewport. + testname: "open popup unanchored", + events: [ "popupshowing thepopup", "popupshown thepopup" ], + test: function(testname, step) { gMenuPopup.openPopup(null, "after_start", 6, 8, false); }, + result: function(testname, step) { + var rect = gMenuPopup.getBoundingClientRect(); + ok(rect.left == 6 && rect.top == 8 && rect.right && rect.bottom, testname); + } +}, +{ + testname: "activate menuitem with mouse", + events: [ "DOMMenuInactive thepopup", "command item3", "DOMMenuItemInactive item3", + "popuphiding thepopup", "popuphidden thepopup" ], + test: function(testname, step) { + var item3 = document.getElementById("item3"); + synthesizeMouse(item3, 4, 4, { }); + }, + result: function(testname, step) { checkClosed("trigger", testname); } +}, +{ + testname: "close popup", + condition: function() { return false; }, + events: [ "popuphiding thepopup", "popuphidden thepopup", + "DOMMenuInactive thepopup" ], + test: function(testname, step) { gMenuPopup.hidePopup(); } +}, +{ + testname: "open popup at screen", + events: [ "popupshowing thepopup", "popupshown thepopup" ], + test: function(testname, step) { + gMenuPopup.openPopupAtScreen(gScreenX + 24, gScreenY + 20, false); + }, + result: function(testname, step) { + var rect = gMenuPopup.getBoundingClientRect(); + ok(rect.left == 24 && rect.top == 20 && rect.right && rect.bottom, testname); + } +}, +{ + // check that pressing a menuitem's accelerator selects it. Note that + // the menuitem with the M accesskey overrides the earlier menuitem that + // begins with M. + testname: "menuitem accelerator", + events: [ "DOMMenuItemActive amenu", "DOMMenuItemInactive amenu", + "DOMMenuInactive thepopup", + "command amenu", "DOMMenuItemInactive amenu", + "popuphiding thepopup", "popuphidden thepopup", + ], + test: function() { synthesizeKey("M", { }); }, + result: function(testname) { checkClosed("trigger", testname); } +}, +{ + testname: "open context popup at screen", + events: [ "popupshowing thepopup", "popupshown thepopup" ], + test: function(testname, step) { + gMenuPopup.openPopupAtScreen(gScreenX + 8, gScreenY + 16, false); + }, + result: function(testname, step) { + var rect = gMenuPopup.getBoundingClientRect(); + ok(rect.left == 8 && rect.top == 16 && rect.right && rect.bottom, testname); + } +}, +{ + // pressing a letter that doesn't correspond to an accelerator, but does + // correspond to the first letter in a menu's label. The menu should not + // close because there is more than one item corresponding to that letter + testname: "menuitem with non accelerator", + events: [ "DOMMenuItemActive one" ], + test: function() { synthesizeKey("O", { }); }, + result: function(testname) { + checkOpen("trigger", testname); + checkActive(gMenuPopup, "one", testname); + } +}, +{ + // pressing the letter again should select the next one that starts with + // that letter + testname: "menuitem with non accelerator again", + events: [ "DOMMenuItemInactive one", "DOMMenuItemActive submenu" ], + test: function() { synthesizeKey("O", { }); }, + result: function(testname) { + // 'submenu' is a menu but it should not be open + checkOpen("trigger", testname); + checkClosed("submenu", testname); + checkActive(gMenuPopup, "submenu", testname); + } +}, +{ + // open the submenu with the cursor right key + testname: "open submenu with cursor right", + events: [ "popupshowing submenupopup", "DOMMenuItemActive submenuitem", + "popupshown submenupopup" ], + test: function() { synthesizeKey("VK_RIGHT", { }); }, + result: function(testname) { + checkOpen("trigger", testname); + checkOpen("submenu", testname); + checkActive(gMenuPopup, "submenu", testname); + checkActive(document.getElementById("submenupopup"), "submenuitem", testname); + } +}, +{ + // close the submenu with the cursor left key + testname: "close submenu with cursor left", + events: [ "popuphiding submenupopup", "popuphidden submenupopup", + "DOMMenuItemInactive submenuitem", "DOMMenuInactive submenupopup", + "DOMMenuItemActive submenu" ], + test: function() { synthesizeKey("VK_LEFT", { }); }, + result: function(testname) { + checkOpen("trigger", testname); + checkClosed("submenu", testname); + checkActive(gMenuPopup, "submenu", testname); + checkActive(document.getElementById("submenupopup"), "", testname); + } +}, +{ + // open the submenu with the enter key + testname: "open submenu with enter", + events: [ "popupshowing submenupopup", "DOMMenuItemActive submenuitem", + "popupshown submenupopup" ], + test: function() { synthesizeKey("VK_ENTER", { }); }, + result: function(testname) { + checkOpen("trigger", testname); + checkOpen("submenu", testname); + checkActive(gMenuPopup, "submenu", testname); + checkActive(document.getElementById("submenupopup"), "submenuitem", testname); + } +}, +{ + // close the submenu with the escape key + testname: "close submenu with escape", + events: [ "popuphiding submenupopup", "popuphidden submenupopup", + "DOMMenuItemInactive submenuitem", "DOMMenuInactive submenupopup", + "DOMMenuItemActive submenu" ], + test: function() { synthesizeKey("VK_ESCAPE", { }); }, + result: function(testname) { + checkOpen("trigger", testname); + checkClosed("submenu", testname); + checkActive(gMenuPopup, "submenu", testname); + checkActive(document.getElementById("submenupopup"), "", testname); + } +}, +{ + // pressing the letter again when the next item is disabled should still + // select the disabled item on Windows, but select the next item on other + // platforms + testname: "menuitem with non accelerator disabled", + events: function() { + if (navigator.platform.indexOf("Win") == 0) + return [ "DOMMenuItemInactive submenu", "DOMMenuItemActive other", + "DOMMenuItemInactive other", "DOMMenuItemActive item1" ]; + else + return [ "DOMMenuItemInactive submenu", "DOMMenuItemActive last", + "DOMMenuItemInactive last", "DOMMenuItemActive item1" ]; + }, + test: function() { synthesizeKey("O", { }); synthesizeKey("F", { }); }, + result: function(testname) { + checkActive(gMenuPopup, "item1", testname); + } +}, +{ + // pressing a letter that doesn't correspond to an accelerator nor the + // first letter of a menu. This should have no effect. + testname: "menuitem with keypress no accelerator found", + test: function() { synthesizeKey("G", { }); }, + result: function(testname) { + checkOpen("trigger", testname); + checkActive(gMenuPopup, "item1", testname); + } +}, +{ + // when only one menuitem starting with that letter exists, it should be + // selected and the menu closed + testname: "menuitem with non accelerator single", + events: [ "DOMMenuItemInactive item1", "DOMMenuItemActive amenu", + "DOMMenuItemInactive amenu", "DOMMenuInactive thepopup", + "command amenu", "DOMMenuItemInactive amenu", + "popuphiding thepopup", "popuphidden thepopup", + ], + test: function() { synthesizeKey("M", { }); }, + result: function(testname) { + checkClosed("trigger", testname); + checkActive(gMenuPopup, "", testname); + } +}, +{ + testname: "open popup with open property", + events: [ "popupshowing thepopup", "popupshown thepopup" ], + test: function(testname, step) { openMenu(gTrigger); }, + result: function(testname, step) { + checkOpen("trigger", testname); + if (gIsMenu) + compareEdge(gTrigger, gMenuPopup, "after_start", 0, 0, testname); + } +}, +{ end: true, + testname: "open submenu with open property", + events: [ "popupshowing submenupopup", "DOMMenuItemActive submenu", + "popupshown submenupopup" ], + test: function(testname, step) { openMenu(document.getElementById("submenu")); }, + result: function(testname, step) { + checkOpen("trigger", testname); + checkOpen("submenu", testname); + // XXXndeakin + // getBoundingClientRect doesn't seem to working right for submenus + // so disable this test for now + // compareEdge(document.getElementById("submenu"), + // document.getElementById("submenupopup"), "end_before", 0, 0, testname); + } +}, +{ + testname: "hidePopup hides entire chain", + events: [ "popuphiding submenupopup", "popuphidden submenupopup", + "popuphiding thepopup", "popuphidden thepopup", + "DOMMenuInactive submenupopup", + "DOMMenuItemInactive submenu", "DOMMenuItemInactive submenu", + "DOMMenuInactive thepopup", ], + test: function() { gMenuPopup.hidePopup(); }, + result: function(testname, step) { + checkClosed("trigger", testname); + checkClosed("submenu", testname); + } +}, +{ + testname: "open submenu with open property without parent open", + test: function(testname, step) { openMenu(document.getElementById("submenu")); }, + result: function(testname, step) { + checkClosed("trigger", testname); + checkClosed("submenu", testname); + } +}, +{ + testname: "open popup with open property and position", + condition: function() { return gIsMenu; }, + events: [ "popupshowing thepopup", "popupshown thepopup" ], + test: function(testname, step) { + gMenuPopup.setAttribute("position", "before_start"); + openMenu(gTrigger); + }, + result: function(testname, step) { + compareEdge(gTrigger, gMenuPopup, "before_start", 0, 0, testname); + } +}, +{ + testname: "close popup with open property", + condition: function() { return gIsMenu; }, + events: [ "popuphiding thepopup", "popuphidden thepopup", + "DOMMenuInactive thepopup" ], + test: function(testname, step) { closeMenu(gTrigger, gMenuPopup); }, + result: function(testname, step) { checkClosed("trigger", testname); } +}, +{ + testname: "open popup with open property, position, anchor and alignment", + condition: function() { return gIsMenu; }, + events: [ "popupshowing thepopup", "popupshown thepopup" ], + autohide: "thepopup", + test: function(testname, step) { + gMenuPopup.setAttribute("position", "start_after"); + gMenuPopup.setAttribute("popupanchor", "topright"); + gMenuPopup.setAttribute("popupalign", "bottomright"); + openMenu(gTrigger); + }, + result: function(testname, step) { + compareEdge(gTrigger, gMenuPopup, "start_after", 0, 0, testname); + } +}, +{ + testname: "open popup with open property, anchor and alignment", + condition: function() { return gIsMenu; }, + events: [ "popupshowing thepopup", "popupshown thepopup" ], + autohide: "thepopup", + test: function(testname, step) { + gMenuPopup.removeAttribute("position"); + gMenuPopup.setAttribute("popupanchor", "bottomright"); + gMenuPopup.setAttribute("popupalign", "topright"); + openMenu(gTrigger); + }, + result: function(testname, step) { + compareEdge(gTrigger, gMenuPopup, "after_end", 0, 0, testname); + gMenuPopup.removeAttribute("popupanchor"); + gMenuPopup.removeAttribute("popupalign"); + } +}, +{ + testname: "focus and cursor down on trigger", + condition: function() { return gIsMenu; }, + events: [ "popupshowing thepopup", "popupshown thepopup" ], + autohide: "thepopup", + test: function(testname, step) { + gTrigger.focus(); + synthesizeKey("VK_DOWN", { altKey: (navigator.platform.indexOf("Mac") == -1) }); + }, + result: function(testname, step) { + checkOpen("trigger", testname); + checkActive(gMenuPopup, "", testname); + } +}, +{ + testname: "focus and cursor up on trigger", + condition: function() { return gIsMenu; }, + events: [ "popupshowing thepopup", "popupshown thepopup" ], + test: function(testname, step) { + gTrigger.focus(); + synthesizeKey("VK_UP", { altKey: (navigator.platform.indexOf("Mac") == -1) }); + }, + result: function(testname, step) { + checkOpen("trigger", testname); + checkActive(gMenuPopup, "", testname); + } +}, +{ + testname: "select and enter on menuitem", + condition: function() { return gIsMenu; }, + events: [ "DOMMenuItemActive item1", "DOMMenuItemInactive item1", + "DOMMenuInactive thepopup", "command item1", + "DOMMenuItemInactive item1", + "popuphiding thepopup", "popuphidden thepopup" ], + test: function(testname, step) { + synthesizeKey("VK_DOWN", { }); + synthesizeKey("VK_ENTER", { }); + }, + result: function(testname, step) { checkClosed("trigger", testname); } +}, +{ + testname: "focus trigger and key to open", + condition: function() { return gIsMenu; }, + events: [ "popupshowing thepopup", "popupshown thepopup" ], + autohide: "thepopup", + test: function(testname, step) { + gTrigger.focus(); + synthesizeKey((navigator.platform.indexOf("Mac") == -1) ? "VK_F4" : " ", { }); + }, + result: function(testname, step) { + checkOpen("trigger", testname); + checkActive(gMenuPopup, "", testname); + } +}, +{ + // the menu should only open when the meta or alt key is not pressed + testname: "focus trigger and key wrong modifier", + condition: function() { return gIsMenu; }, + test: function(testname, step) { + gTrigger.focus(); + if (navigator.platform.indexOf("Mac") == -1) + synthesizeKey("", { metaKey: true }); + else + synthesizeKey("VK_F4", { altKey: true }); + }, + result: function(testname, step) { + checkClosed("trigger", testname); + } +}, +{ + testname: "mouse click on disabled menu", + condition: function() { return gIsMenu; }, + test: function(testname, step) { + gTrigger.setAttribute("disabled", "true"); + synthesizeMouse(gTrigger, 4, 4, { }); + }, + result: function(testname, step) { + checkClosed("trigger", testname); + gTrigger.removeAttribute("disabled"); + } +}, +{ + // openPopup should open the menu synchronously, however popupshown + // is fired asynchronously + testname: "openPopup synchronous", + events: [ "popupshowing thepopup", "popupshowing submenupopup", + "popupshown thepopup", "DOMMenuItemActive submenu", + "popupshown submenupopup" ], + test: function(testname, step) { + gMenuPopup.openPopup(gTrigger, "after_start", 0, 0, false, true); + document.getElementById("submenupopup"). + openPopup(gTrigger, "end_before", 0, 0, false, true); + checkOpen("trigger", testname); + checkOpen("submenu", testname); + } +}, +{ + // remove the content nodes for the popup + testname: "remove content", + test: function(testname, step) { + var submenupopup = document.getElementById("submenupopup"); + submenupopup.parentNode.removeChild(submenupopup); + var popup = document.getElementById("thepopup"); + popup.parentNode.removeChild(popup); + } +}, + +]; diff --git a/toolkit/content/tests/widgets/test_menubar.xul b/toolkit/content/tests/widgets/test_menubar.xul new file mode 100644 index 00000000000..7124cc8aba4 --- /dev/null +++ b/toolkit/content/tests/widgets/test_menubar.xul @@ -0,0 +1,31 @@ + + + + + + + Menubar Popup Tests + + + + + + +

+

+ +
+
+ + +
diff --git a/toolkit/content/tests/widgets/test_menuchecks.xul b/toolkit/content/tests/widgets/test_menuchecks.xul new file mode 100644 index 00000000000..5c14ee7c6d0 --- /dev/null +++ b/toolkit/content/tests/widgets/test_menuchecks.xul @@ -0,0 +1,34 @@ + + + + + + + Menu Checkbox and Radio Tests + + + + + + + +

+

+ +
+
+ + +
diff --git a/toolkit/content/tests/widgets/test_popup_attribute.xul b/toolkit/content/tests/widgets/test_popup_attribute.xul new file mode 100644 index 00000000000..85fc9be1722 --- /dev/null +++ b/toolkit/content/tests/widgets/test_popup_attribute.xul @@ -0,0 +1,31 @@ + + + + + + + Popup Attribute Tests + + + + + + +

+

+ +
+
+ + +
diff --git a/toolkit/content/tests/widgets/test_popup_button.xul b/toolkit/content/tests/widgets/test_popup_button.xul new file mode 100644 index 00000000000..483756d5251 --- /dev/null +++ b/toolkit/content/tests/widgets/test_popup_button.xul @@ -0,0 +1,31 @@ + + + + + + + Menu Button Popup Tests + + + + + + +

+

+ +
+
+ + +
diff --git a/toolkit/content/tests/widgets/test_popup_preventdefault.xul b/toolkit/content/tests/widgets/test_popup_preventdefault.xul new file mode 100644 index 00000000000..98d99f1618d --- /dev/null +++ b/toolkit/content/tests/widgets/test_popup_preventdefault.xul @@ -0,0 +1,79 @@ + + + + + + + Popup Prevent Default Tests + + + + + + + + + + +

+

+ +
+
+ + +
diff --git a/toolkit/content/tests/widgets/test_tooltip.xul b/toolkit/content/tests/widgets/test_tooltip.xul new file mode 100644 index 00000000000..1f985e382ba --- /dev/null +++ b/toolkit/content/tests/widgets/test_tooltip.xul @@ -0,0 +1,32 @@ + + + + + + + Tooltip Tests + + + + + + + +

+

+ +
+
+ + +
diff --git a/toolkit/content/tests/widgets/window_menubar.xul b/toolkit/content/tests/widgets/window_menubar.xul new file mode 100644 index 00000000000..6b163ebd0a9 --- /dev/null +++ b/toolkit/content/tests/widgets/window_menubar.xul @@ -0,0 +1,501 @@ + + + + + + Popup Tests + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/content/tests/widgets/window_menuchecks.xul b/toolkit/content/tests/widgets/window_menuchecks.xul new file mode 100644 index 00000000000..158b35aab56 --- /dev/null +++ b/toolkit/content/tests/widgets/window_menuchecks.xul @@ -0,0 +1,135 @@ + + + + + + Menu Checkbox and Radio Tests + + + + + + + + + + diff --git a/toolkit/content/tests/widgets/window_popup_attribute.xul b/toolkit/content/tests/widgets/window_popup_attribute.xul new file mode 100644 index 00000000000..a72a60f075f --- /dev/null +++ b/toolkit/content/tests/widgets/window_popup_attribute.xul @@ -0,0 +1,35 @@ + + + + + + Popup Attribute Tests + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/toolkit/content/tests/widgets/window_popup_button.xul b/toolkit/content/tests/widgets/window_popup_button.xul new file mode 100644 index 00000000000..68989ab7c7d --- /dev/null +++ b/toolkit/content/tests/widgets/window_popup_button.xul @@ -0,0 +1,35 @@ + + + + + + Popup Tests + + + + + + + + + diff --git a/toolkit/content/tests/widgets/window_tooltip.xul b/toolkit/content/tests/widgets/window_tooltip.xul new file mode 100644 index 00000000000..859f34995ea --- /dev/null +++ b/toolkit/content/tests/widgets/window_tooltip.xul @@ -0,0 +1,188 @@ + + + + + + Tooltip Tests + + + + + + + +