summaryrefslogtreecommitdiffstats
path: root/toolkit/content/tests/chrome/test_menulist.xhtml
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/content/tests/chrome/test_menulist.xhtml')
-rw-r--r--toolkit/content/tests/chrome/test_menulist.xhtml350
1 files changed, 350 insertions, 0 deletions
diff --git a/toolkit/content/tests/chrome/test_menulist.xhtml b/toolkit/content/tests/chrome/test_menulist.xhtml
new file mode 100644
index 0000000000..5917785b56
--- /dev/null
+++ b/toolkit/content/tests/chrome/test_menulist.xhtml
@@ -0,0 +1,350 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+
+<window title="Menulist Tests"
+ onload="setTimeout(testtag_menulists, 0);"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+ <script type="application/javascript" src="xul_selectcontrol.js"></script>
+
+<vbox id="scroller" style="overflow: auto; height: 60px">
+ <menulist id="menulist" onpopupshown="test_menulist_open(this, this.parentNode)"
+ onpopuphidden="$('menulist-in-listbox').open = true;">
+ <menupopup id="menulist-popup"/>
+ </menulist>
+ <button label="Two"/>
+ <button label="Three"/>
+</vbox>
+<richlistbox id="scroller-in-listbox" style="overflow: auto; height: 60px">
+ <richlistitem allowevents="true">
+ <menulist id="menulist-in-listbox" onpopupshown="test_menulist_open(this, this.parentNode.parentNode)"
+ onpopuphidden="SimpleTest.executeSoon(() => checkScrollAndFinish().catch(ex => ok(false, ex)));">
+ <menupopup id="menulist-in-listbox-popup">
+ <menuitem label="One" value="one"/>
+ <menuitem label="Two" value="two"/>
+ </menupopup>
+ </menulist>
+ </richlistitem>
+ <richlistitem><label value="Two"/></richlistitem>
+ <richlistitem><label value="Three"/></richlistitem>
+ <richlistitem><label value="Four"/></richlistitem>
+ <richlistitem><label value="Five"/></richlistitem>
+ <richlistitem><label value="Six"/></richlistitem>
+</richlistbox>
+
+<hbox>
+ <menulist id="menulist-size">
+ <menupopup>
+ <menuitem label="Menuitem Label" style="width: 200px"/>
+ </menupopup>
+ </menulist>
+</hbox>
+
+<menulist id="menulist-initwithvalue" value="two">
+ <menupopup>
+ <menuitem label="One" value="one"/>
+ <menuitem label="Two" value="two"/>
+ <menuitem label="Three" value="three"/>
+ </menupopup>
+</menulist>
+<menulist id="menulist-initwithselected" value="two">
+ <menupopup>
+ <menuitem label="One" value="one"/>
+ <menuitem label="Two" value="two"/>
+ <menuitem label="Three" value="three" selected="true"/>
+ </menupopup>
+</menulist>
+
+<menulist id="menulist-clipped">
+ <menupopup style="height: 65px">
+ <menuitem label="One" value="one"/>
+ <menuitem label="Two" value="two"/>
+ <menuitem label="Three" value="three"/>
+ <menuitem label="Four" value="four"/>
+ <menuitem label="Five" value="five" selected="true"/>
+ <menuitem label="Six" value="six"/>
+ <menuitem label="Seven" value="seven"/>
+ <menuitem label="Eight" value="eight"/>
+ </menupopup>
+</menulist>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+function waitForEvent(subject, eventName, checkFn) {
+ return new Promise(resolve => {
+ subject.addEventListener(eventName, function listener(event) {
+ if (checkFn && !checkFn(event)) {
+ return;
+ }
+ subject.removeEventListener(eventName, listener);
+ SimpleTest.executeSoon(() => resolve(event));
+ });
+ });
+}
+
+SimpleTest.waitForExplicitFinish();
+
+function testtag_menulists()
+{
+ testtag_menulist_UI_start($("menulist"), false);
+}
+
+function testtag_menulist_UI_start(element)
+{
+ // check the menupopup property
+ var popup = element.menupopup;
+ ok(popup && popup.localName == "menupopup" &&
+ popup.parentNode == element, "menupopup");
+
+ // test the interfaces that menulist implements
+ test_nsIDOMXULMenuListElement(element);
+}
+
+function testtag_menulist_UI_finish(element)
+{
+ element.value = "";
+
+ test_nsIDOMXULSelectControlElement(element, "menuitem", null);
+
+ $("menulist").open = true;
+}
+
+function test_nsIDOMXULMenuListElement(element)
+{
+ is(element.open, false, "open");
+
+ element.appendItem("Item One", "one");
+ var seconditem = element.appendItem("Item Two", "two");
+ var thirditem = element.appendItem("Item Three", "three");
+ element.appendItem("Item Four", "four");
+
+ seconditem.image = "happy.png";
+ seconditem.setAttribute("description", "This is the second description");
+ thirditem.image = "happy.png";
+ thirditem.setAttribute("description", "This is the third description");
+
+ // check the image and description properties
+ element.selectedIndex = 1;
+ is(element.image, "happy.png", "image set to selected");
+ is(element.description, "This is the second description", "description set to selected");
+ element.selectedIndex = -1;
+ is(element.image, "", "image set when none selected");
+ is(element.description, "", "description set when none selected");
+ element.selectedIndex = 2;
+ is(element.image, "happy.png", "image set to selected again");
+ is(element.description, "This is the third description", "description set to selected again");
+
+ // check that changing the properties of the selected item changes the menulist's properties
+ let properties = [{attr: "label", value: "Item Number Three"},
+ {attr: "value", value: "item-three"},
+ {attr: "image", value: "smile.png"},
+ {attr: "description", value: "Changed description"}];
+ test_nsIDOMXULMenuListElement_properties(element, thirditem, properties);
+}
+
+function test_nsIDOMXULMenuListElement_properties(element, thirditem, properties)
+{
+ let {attr, value} = properties.shift();
+ let last = !properties.length;
+
+ let mutObserver = new MutationObserver(() => {
+ is(element.getAttribute(attr), value, `${attr} modified`);
+ done();
+ });
+ mutObserver.observe(element, { attributeFilter: [attr] });
+
+ let failureTimeout = setTimeout(() => {
+ ok(false, `${attr} should have updated`);
+ done();
+ }, 2000);
+
+ function done()
+ {
+ clearTimeout(failureTimeout);
+ mutObserver.disconnect();
+ if (!last) {
+ test_nsIDOMXULMenuListElement_properties(element, thirditem, properties);
+ }
+ else {
+ test_nsIDOMXULMenuListElement_unselected(element, thirditem);
+ }
+ }
+
+ thirditem.setAttribute(attr, value)
+}
+
+function test_nsIDOMXULMenuListElement_unselected(element, thirditem)
+{
+ let seconditem = thirditem.previousElementSibling;
+ seconditem.label = "Changed Label 2";
+ is(element.label, "Item Number Three", "label of another item modified");
+
+ element.selectedIndex = 0;
+ is(element.image, "", "image set to selected with no image");
+ is(element.description, "", "description set to selected with no description");
+ test_nsIDOMXULMenuListElement_finish(element);
+}
+
+function test_nsIDOMXULMenuListElement_finish(element)
+{
+ // check the removeAllItems method
+ element.appendItem("An Item", "anitem");
+ element.appendItem("Another Item", "anotheritem");
+ element.removeAllItems();
+ is(element.itemCount, 0, "removeAllItems");
+
+ testtag_menulist_UI_finish(element);
+}
+
+function test_menulist_open(element, scroller)
+{
+ element.appendItem("Scroll Item 1", "scrollitem1");
+ element.appendItem("Scroll Item 2", "scrollitem2");
+ element.focus();
+ element.selectedIndex = 0;
+
+/*
+ // bug 530504, mousewheel while menulist is open should not scroll menulist
+ // items or parent
+ var scrolled = false;
+ var mouseScrolled = function (event) { scrolled = true; }
+ window.addEventListener("DOMMouseScroll", mouseScrolled, false);
+ synthesizeWheel(element, 2, 2, { deltaY: 10,
+ deltaMode: WheelEvent.DOM_DELTA_LINE });
+ is(scrolled, true, "mousescroll " + element.id);
+ is(scroller.scrollTop, 0, "scroll position on mousescroll " + element.id);
+ window.removeEventListener("DOMMouseScroll", mouseScrolled, false);
+*/
+
+ // bug 543065, hovering the mouse over an item should highlight it, not
+ // scroll the parent, and not change the selected index.
+ var item = element.menupopup.childNodes[1];
+
+ synthesizeMouse(element.menupopup.childNodes[1], 2, 2, { type: "mousemove" });
+ synthesizeMouse(element.menupopup.childNodes[1], 6, 6, { type: "mousemove" });
+ is(element.activeChild, item, "activeChild after menu highlight " + element.id);
+ is(element.selectedIndex, 0, "selectedIndex after menu highlight " + element.id);
+ is(scroller.scrollTop, 0, "scroll position after menu highlight " + element.id);
+
+ element.open = false;
+}
+
+async function checkScrollAndFinish()
+{
+ is($("scroller").scrollTop, 0, "mousewheel on menulist does not scroll vbox parent");
+ is($("scroller-in-listbox").scrollTop, 0, "mousewheel on menulist does not scroll listbox parent");
+
+ let menulist = $("menulist-size");
+ let shownPromise = waitForEvent(menulist, "popupshown");
+ menulist.open = true;
+ await shownPromise;
+
+ sendKey("ALT");
+ is(menulist.menupopup.state, "open", "alt doesn't close menulist");
+ menulist.open = false;
+
+ await dragScroll();
+}
+
+async function dragScroll()
+{
+ let menulist = $("menulist-clipped");
+
+ let shownPromise = waitForEvent(menulist, "popupshown");
+ menulist.open = true;
+ await shownPromise;
+
+ let popup = menulist.menupopup;
+ let getScrollPos = () => popup.scrollBox.scrollbox.scrollTop;
+ let scrollPos = getScrollPos();
+ let popupRect = popup.getBoundingClientRect();
+
+ // First, check that scrolling does not occur when the mouse is moved over the
+ // anchor button but not the popup yet.
+ synthesizeMouseAtPoint(popupRect.left + 5, popupRect.top - 10, { type: "mousemove" });
+ is(getScrollPos(), scrollPos, "scroll position after mousemove over button should not change");
+
+ synthesizeMouseAtPoint(popupRect.left + 20, popupRect.top + 10, { type: "mousemove" });
+ synthesizeMouseAtPoint(popupRect.left + 20, popupRect.top + 10, { type: "mousedown", buttons: 1 });
+
+ // Dragging above the popup scrolls it up.
+ let scrolledPromise = waitForEvent(popup, "scroll", false,
+ () => getScrollPos() < scrollPos - 5);
+ synthesizeMouseAtPoint(popupRect.left + 20, popupRect.top - 20, { type: "mousemove", buttons: 1 });
+ await scrolledPromise;
+ ok(true, "scroll position at drag up");
+
+ // Dragging below the popup scrolls it down.
+ scrollPos = getScrollPos();
+ scrolledPromise = waitForEvent(popup, "scroll", false,
+ () => getScrollPos() > scrollPos + 5);
+ synthesizeMouseAtPoint(popupRect.left + 20, popupRect.bottom + 20, { type: "mousemove", buttons: 1 });
+ await scrolledPromise;
+ ok(true, "scroll position at drag down");
+
+ // Releasing the mouse button and moving the mouse does not change the scroll position.
+ scrollPos = getScrollPos();
+ synthesizeMouseAtPoint(popupRect.left + 20, popupRect.bottom + 25, { type: "mouseup" });
+ is(getScrollPos(), scrollPos, "scroll position at mouseup should not change");
+
+ synthesizeMouseAtPoint(popupRect.left + 20, popupRect.bottom + 20, { type: "mousemove" });
+ is(getScrollPos(), scrollPos, "scroll position at mousemove after mouseup should not change");
+
+ // Now check dragging with a mousedown on an item. Make sure the element is
+ // visible, as the asynchronous scrolling may have moved it out of view.
+ popup.childNodes[4].scrollIntoView({ block: "nearest", behavior: "instant" });
+ let menuRect = popup.childNodes[4].getBoundingClientRect();
+ synthesizeMouseAtPoint(menuRect.left + 5, menuRect.top + 5, { type: "mousedown", buttons: 1 });
+
+ // Dragging below the popup scrolls it down.
+ scrolledPromise = waitForEvent(popup, "scroll", false,
+ () => getScrollPos() > scrollPos + 5);
+ synthesizeMouseAtPoint(popupRect.left + 20, popupRect.bottom + 20, { type: "mousemove", buttons: 1 });
+ await scrolledPromise;
+ ok(true, "scroll position at drag down from item");
+
+ // Dragging above the popup scrolls it up.
+ scrollPos = getScrollPos();
+ scrolledPromise = waitForEvent(popup, "scroll", false,
+ () => getScrollPos() < scrollPos - 5);
+ synthesizeMouseAtPoint(popupRect.left + 20, popupRect.top - 20, { type: "mousemove", buttons: 1 });
+ await scrolledPromise;
+ ok(true, "scroll position at drag up from item");
+
+ scrollPos = getScrollPos();
+ synthesizeMouseAtPoint(popupRect.left + 20, popupRect.bottom + 25, { type: "mouseup" });
+ is(getScrollPos(), scrollPos, "scroll position at mouseup should not change");
+
+ synthesizeMouseAtPoint(popupRect.left + 20, popupRect.bottom + 20, { type: "mousemove" });
+ is(getScrollPos(), scrollPos, "scroll position at mousemove after mouseup should not change");
+
+ menulist.open = false;
+
+ let mouseMoveTarget = null;
+ popup.childNodes[4].click();
+ addEventListener("mousemove", function checkMouseMove(event) {
+ mouseMoveTarget = event.target;
+ }, {once: true});
+ synthesizeMouseAtPoint(popupRect.left + 20, popupRect.bottom + 20, { type: "mousemove" });
+ isnot(mouseMoveTarget, popup, "clicking on item when popup closed doesn't start dragging");
+
+ SimpleTest.finish();
+}
+
+]]>
+</script>
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+<p id="display">
+</p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+
+</window>