diff --git a/browser/metro/base/tests/Makefile.in b/browser/metro/base/tests/Makefile.in index 046c87c9f36..b91b90b26a9 100644 --- a/browser/metro/base/tests/Makefile.in +++ b/browser/metro/base/tests/Makefile.in @@ -25,6 +25,7 @@ BROWSER_TESTS = \ browser_plugin_input_keyboard.js \ browser_context_menu_tests.js \ browser_context_menu_tests_01.html \ + browser_context_menu_tests_02.html \ $(NULL) BROWSER_TEST_RESOURCES = \ diff --git a/browser/metro/base/tests/browser_context_menu_tests.js b/browser/metro/base/tests/browser_context_menu_tests.js index d78af29916b..b6365e0e13e 100644 --- a/browser/metro/base/tests/browser_context_menu_tests.js +++ b/browser/metro/base/tests/browser_context_menu_tests.js @@ -20,6 +20,226 @@ function debugClipFlavors(aClip) } } +// XXX won't work with out of process content +function emptyClipboard() { + Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard) + .emptyClipboard(Ci.nsIClipboard.kGlobalClipboard); +} + +// Image context menu tests +gTests.push({ + desc: "text context menu", + run: function test() { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + + info(chromeRoot + "browser_context_menu_tests_02.html"); + yield addTab(chromeRoot + "browser_context_menu_tests_02.html"); + + purgeEventQueue(); + + let win = Browser.selectedTab.browser.contentWindow; + + yield hideContextUI(); + + //////////////////////////////////////////////////////////// + // Context menu in content on selected text + + // select some text + let span = win.document.getElementById("text1"); + win.getSelection().selectAllChildren(span); + + // invoke selection context menu + let promise = waitForEvent(document, "popupshown"); + sendContextMenuClickToElement(win, span, 85, 10); + yield promise; + ok(promise && !(promise instanceof Error), "promise error"); + + // should be visible + ok(ContextMenuUI._menuPopup._visible, "is visible"); + + // selected text context: + checkContextUIMenuItemVisibility(["context-copy", + "context-search"]); + + promise = waitForEvent(document, "popuphidden"); + ContextMenuUI.hide(); + yield promise; + ok(promise && !(promise instanceof Error), "promise error"); + win.getSelection().removeAllRanges(); + + //////////////////////////////////////////////////////////// + // Context menu in content on selected text that includes a link + + // invoke selection with link context menu + let link = win.document.getElementById("text2-link"); + win.getSelection().selectAllChildren(link); + promise = waitForEvent(document, "popupshown"); + sendContextMenuClickToElement(win, link, 40, 10); + yield promise; + ok(promise && !(promise instanceof Error), "promise error"); + + // should be visible + ok(ContextMenuUI._menuPopup._visible, "is visible"); + + // selected text context: + checkContextUIMenuItemVisibility(["context-copy", + "context-search", + "context-open-in-new-tab", + "context-copy-link"]); + + promise = waitForEvent(document, "popuphidden"); + ContextMenuUI.hide(); + yield promise; + ok(promise && !(promise instanceof Error), "promise error"); + win.getSelection().removeAllRanges(); + + //////////////////////////////////////////////////////////// + // Context menu in content on a link + + link = win.document.getElementById("text2-link"); + promise = waitForEvent(document, "popupshown"); + sendContextMenuClickToElement(win, link, 40, 10); + yield promise; + ok(promise && !(promise instanceof Error), "promise error"); + + // should be visible + ok(ContextMenuUI._menuPopup._visible, "is visible"); + + // selected text context: + checkContextUIMenuItemVisibility(["context-open-in-new-tab", + "context-copy-link", + "context-bookmark-link"]); + + promise = waitForEvent(document, "popuphidden"); + ContextMenuUI.hide(); + yield promise; + ok(promise && !(promise instanceof Error), "promise error"); + + //////////////////////////////////////////////////////////// + // context in input with no selection, no data on clipboard + + emptyClipboard(); + + let input = win.document.getElementById("text3-input"); + promise = waitForEvent(document, "popupshown"); + sendContextMenuClickToElement(win, input, 20, 10); + yield promise; + ok(promise && !(promise instanceof Error), "promise error"); + + // should be visible + ok(ContextMenuUI._menuPopup._visible, "is visible"); + + checkContextUIMenuItemVisibility(["context-copy", + "context-select", + "context-select-all"]); + + // copy menu item should copy all text + let menuItem = document.getElementById("context-copy"); + ok(menuItem, "menu item exists"); + ok(!menuItem.hidden, "menu item visible"); + + let popupPromise = waitForEvent(document, "popuphidden"); + EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win); + yield popupPromise; + ok(popupPromise && !(popupPromise instanceof Error), "promise error"); + let string = SpecialPowers.getClipboardData("text/unicode"); + ok(string, "hello, I'm sorry but I must be going.", "copy all"); + + emptyClipboard(); + + //////////////////////////////////////////////////////////// + // context in input with text selection, no data on clipboard + + input = win.document.getElementById("text3-input"); + input.select(); + promise = waitForEvent(document, "popupshown"); + sendContextMenuClickToElement(win, input, 20, 10); + yield promise; + ok(promise && !(promise instanceof Error), "promise error"); + + // should be visible + ok(ContextMenuUI._menuPopup._visible, "is visible"); + + // selected text context: + checkContextUIMenuItemVisibility(["context-copy", + "context-search"]); + + promise = waitForEvent(document, "popuphidden"); + ContextMenuUI.hide(); + yield promise; + ok(promise && !(promise instanceof Error), "promise error"); + + //////////////////////////////////////////////////////////// + // context in input with no selection, data on clipboard + + SpecialPowers.clipboardCopyString("foo"); + input = win.document.getElementById("text3-input"); + input.select(); + promise = waitForEvent(document, "popupshown"); + sendContextMenuClickToElement(win, input, 20, 10); + yield promise; + ok(promise && !(promise instanceof Error), "promise error"); + + // should be visible + ok(ContextMenuUI._menuPopup._visible, "is visible"); + + // selected text context: + checkContextUIMenuItemVisibility(["context-copy", + "context-search", + "context-paste"]); + + promise = waitForEvent(document, "popuphidden"); + ContextMenuUI.hide(); + yield promise; + ok(promise && !(promise instanceof Error), "promise error"); + + //////////////////////////////////////////////////////////// + // context in empty input, data on clipboard (paste operation) + + SpecialPowers.clipboardCopyString("foo"); + input = win.document.getElementById("text3-input"); + input.value = ""; + + promise = waitForEvent(document, "popupshown"); + sendContextMenuClickToElement(win, input, 20, 10); + yield promise; + ok(promise && !(promise instanceof Error), "promise error"); + + // should be visible + ok(ContextMenuUI._menuPopup._visible, "is visible"); + + // selected text context: + checkContextUIMenuItemVisibility(["context-paste"]); + + promise = waitForEvent(document, "popuphidden"); + ContextMenuUI.hide(); + yield promise; + ok(promise && !(promise instanceof Error), "promise error"); + + //////////////////////////////////////////////////////////// + // context in empty input, no data on clipboard (??) + + emptyClipboard(); + + input = win.document.getElementById("text3-input"); + input.value = ""; + + promise = waitForEvent(Elements.tray, "transitionend"); + sendContextMenuClickToElement(win, input, 20, 10); + yield promise; + ok(promise && !(promise instanceof Error), "promise error"); + + // should *not* be visible + ok(!ContextMenuUI._menuPopup._visible, "is visible"); + + // the test above will invoke the app bar + yield hideContextUI(); + + Browser.closeTab(Browser.selectedTab); + purgeEventQueue(); + } +}); + // Image context menu tests gTests.push({ desc: "image context menu", @@ -31,8 +251,14 @@ gTests.push({ let win = Browser.selectedTab.browser.contentWindow; + purgeEventQueue(); + yield hideContextUI(); + // If we don't do this, sometimes the first sendContextMenuClick + // will trigger the app bar. + yield waitForImageLoad(win, "image01"); + //////////////////////////////////////////////////////////// // Context menu options @@ -46,7 +272,10 @@ gTests.push({ ok(ContextMenuUI._menuPopup._visible, "is visible"); - checkContextUIMenuItemCount(4); + checkContextUIMenuItemVisibility(["context-save-image-lib", + "context-copy-image", + "context-copy-image-loc", + "context-open-image-tab"]); //////////////////////////////////////////////////////////// // Save to image library @@ -85,7 +314,7 @@ gTests.push({ // Copy image let promise = waitForEvent(document, "popupshown"); - sendContextMenuClick(win, 30, 30); + sendContextMenuClick(win, 20, 20); yield promise; ok(promise && !(promise instanceof Error), "promise error"); ok(ContextMenuUI._menuPopup._visible, "is visible"); @@ -102,13 +331,13 @@ gTests.push({ let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard); let flavors = ["image/png"]; - ok(clip.hasDataMatchingFlavors(flavors, flavors.length, Ci.nsIClipboard.kGlobalClipboard), "clip has my flavor"); + ok(clip.hasDataMatchingFlavors(flavors, flavors.length, Ci.nsIClipboard.kGlobalClipboard), "clip has my png flavor"); //////////////////////////////////////////////////////////// // Copy image location promise = waitForEvent(document, "popupshown"); - sendContextMenuClick(win, 60, 60); + sendContextMenuClick(win, 30, 30); yield promise; ok(promise && !(promise instanceof Error), "promise error"); ok(ContextMenuUI._menuPopup._visible, "is visible"); @@ -125,7 +354,7 @@ gTests.push({ let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard); let flavors = ["text/unicode"]; - ok(clip.hasDataMatchingFlavors(flavors, flavors.length, Ci.nsIClipboard.kGlobalClipboard), "clip has my flavor"); + ok(clip.hasDataMatchingFlavors(flavors, flavors.length, Ci.nsIClipboard.kGlobalClipboard), "clip has my text flavor"); let xfer = Cc["@mozilla.org/widget/transferable;1"]. createInstance(Ci.nsITransferable); @@ -142,7 +371,7 @@ gTests.push({ // Open image in new tab promise = waitForEvent(document, "popupshown"); - sendContextMenuClick(win, 60, 60); + sendContextMenuClick(win, 40, 40); yield promise; ok(promise && !(promise instanceof Error), "promise error"); ok(ContextMenuUI._menuPopup._visible, "is visible"); diff --git a/browser/metro/base/tests/browser_context_menu_tests_01.html b/browser/metro/base/tests/browser_context_menu_tests_01.html index 4ac8d6d537f..fe177e15b11 100644 --- a/browser/metro/base/tests/browser_context_menu_tests_01.html +++ b/browser/metro/base/tests/browser_context_menu_tests_01.html @@ -7,7 +7,7 @@
- +
diff --git a/browser/metro/base/tests/browser_context_menu_tests_02.html b/browser/metro/base/tests/browser_context_menu_tests_02.html new file mode 100644 index 00000000000..46d56aee9e4 --- /dev/null +++ b/browser/metro/base/tests/browser_context_menu_tests_02.html @@ -0,0 +1,18 @@ + + + + + + +
+ hello, I'm sorry but I must be going. +
+
+ hello, I'm sorry but I must be going. +
+
+ +
+ + \ No newline at end of file diff --git a/browser/metro/base/tests/head.js b/browser/metro/base/tests/head.js index 5f5cf2830c2..2d758ee673e 100644 --- a/browser/metro/base/tests/head.js +++ b/browser/metro/base/tests/head.js @@ -32,13 +32,33 @@ function checkContextUIMenuItemCount(aCount) is(visibleCount, aCount, "command list count"); } +function checkContextUIMenuItemVisibility(aVisibleList) +{ + let errors = 0; + for (let idx = 0; idx < ContextMenuUI._commands.childNodes.length; idx++) { + let item = ContextMenuUI._commands.childNodes[idx]; + if (aVisibleList.indexOf(item.id) != -1 && item.hidden) { + // item should be visible + errors++; + info("should be visible:" + item.id); + } else if (aVisibleList.indexOf(item.id) == -1 && !item.hidden) { + // item should be hidden + errors++; + info("should be hidden:" + item.id); + } + } + is(errors, 0, "context menu item list visibility"); +} + /*============================================================================= Asynchronous Metro ui helpers =============================================================================*/ function hideContextUI() { + purgeEventQueue(); if (ContextUI.isVisible) { + info("is visible, waiting..."); let promise = waitForEvent(Elements.tray, "transitionend"); ContextUI.dismiss(); return promise; @@ -93,6 +113,7 @@ function addTab(aUrl) { * @returns a Promise that resolves to the received event, or to an Error */ function waitForEvent(aSubject, aEventName, aTimeoutMs) { + info("waitForEvent: on " + aSubject + " event: " + aEventName); let eventDeferred = Promise.defer(); let timeoutMs = aTimeoutMs || kDefaultWait; let timerID = setTimeout(function wfe_canceller() { @@ -189,6 +210,23 @@ function waitForCondition(aCondition, aTimeoutMs, aIntervalMs) { return deferred.promise; } +/* + * Waits for an image in a page to load. Wrapper around waitForCondition. + * + * @param aWindow the tab or window that contains the image. + * @param aImageId the id of the image in the page. + * @returns a Promise that resolves to true, or to an Error + */ +function waitForImageLoad(aWindow, aImageId) { + let elem = aWindow.document.getElementById(aImageId); + return waitForCondition(function () { + let request = elem.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST); + if (request && (request.imageStatus & request.STATUS_SIZE_AVAILABLE)) + return true; + return false; + }, 5000, 100); +} + /** * Waits a specified number of miliseconds for an observer event. * @@ -339,6 +377,14 @@ function sendContextMenuClick(aWindow, aX, aY) { 1, Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH); } +function sendContextMenuClickToElement(aWindow, aElement, aX, aY) { + let utils = aWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor) + .getInterface(Components.interfaces.nsIDOMWindowUtils); + let rect = aElement.getBoundingClientRect(); + utils.sendMouseEventToWindow("contextmenu", rect.left + aX, rect.top + aY, 2, 1, 0, true, + 1, Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH); +} + /*============================================================================= System utilities =============================================================================*/