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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+