michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: let gNavBar = document.getElementById(CustomizableUI.AREA_NAVBAR); michael@0: let gOverflowList = document.getElementById(gNavBar.getAttribute("overflowtarget")); michael@0: michael@0: const kBookmarksButton = "bookmarks-menu-button"; michael@0: const kBookmarksItems = "personal-bookmarks"; michael@0: const kOriginalWindowWidth = window.outerWidth; michael@0: const kSmallWidth = 400; michael@0: michael@0: /** michael@0: * Helper function that opens the bookmarks menu, and returns a Promise that michael@0: * resolves as soon as the menu is ready for interaction. michael@0: */ michael@0: function bookmarksMenuPanelShown() { michael@0: let deferred = Promise.defer(); michael@0: let bookmarksMenuPopup = document.getElementById("BMB_bookmarksPopup"); michael@0: let onTransitionEnd = (e) => { michael@0: if (e.target == bookmarksMenuPopup) { michael@0: bookmarksMenuPopup.removeEventListener("transitionend", onTransitionEnd); michael@0: deferred.resolve(); michael@0: } michael@0: } michael@0: bookmarksMenuPopup.addEventListener("transitionend", onTransitionEnd); michael@0: return deferred.promise; michael@0: } michael@0: michael@0: /** michael@0: * Checks that the placesContext menu is correctly attached to the michael@0: * controller of some view. Returns a Promise that resolves as soon michael@0: * as the context menu is closed. michael@0: * michael@0: * @param aItemWithContextMenu the item that we need to synthesize hte michael@0: * right click on in order to open the context menu. michael@0: */ michael@0: function checkPlacesContextMenu(aItemWithContextMenu) { michael@0: return Task.spawn(function* () { michael@0: let contextMenu = document.getElementById("placesContext"); michael@0: let newBookmarkItem = document.getElementById("placesContext_new:bookmark"); michael@0: let shownPromise = popupShown(contextMenu); michael@0: EventUtils.synthesizeMouseAtCenter(aItemWithContextMenu, michael@0: {type: "contextmenu", button: 2}); michael@0: yield shownPromise; michael@0: michael@0: ok(!newBookmarkItem.hasAttribute("disabled"), michael@0: "New bookmark item shouldn't be disabled"); michael@0: michael@0: yield closePopup(contextMenu); michael@0: }); michael@0: } michael@0: michael@0: /** michael@0: * Opens the bookmarks menu panel, and then opens each of the "special" michael@0: * submenus in that list. Then it checks that those submenu's context menus michael@0: * are properly hooked up to a controller. michael@0: */ michael@0: function checkSpecialContextMenus() { michael@0: return Task.spawn(function* () { michael@0: let contextMenu = document.getElementById("placesContext"); michael@0: let bookmarksMenuButton = document.getElementById(kBookmarksButton); michael@0: let bookmarksMenuPopup = document.getElementById("BMB_bookmarksPopup"); michael@0: michael@0: const kSpecialItemIDs = { michael@0: "BMB_bookmarksToolbar": "BMB_bookmarksToolbarPopup", michael@0: "BMB_unsortedBookmarks": "BMB_unsortedBookmarksPopup", michael@0: }; michael@0: michael@0: // Open the bookmarks menu button context menus and ensure that michael@0: // they have the proper views attached. michael@0: let shownPromise = bookmarksMenuPanelShown(); michael@0: let dropmarker = document.getAnonymousElementByAttribute(bookmarksMenuButton, michael@0: "anonid", "dropmarker"); michael@0: EventUtils.synthesizeMouseAtCenter(dropmarker, {}); michael@0: info("Waiting for bookmarks menu popup to show after clicking dropmarker.") michael@0: yield shownPromise; michael@0: michael@0: for (let menuID in kSpecialItemIDs) { michael@0: let menuItem = document.getElementById(menuID); michael@0: let menuPopup = document.getElementById(kSpecialItemIDs[menuID]); michael@0: let shownPromise = popupShown(menuPopup); michael@0: menuPopup.openPopup(menuItem, null, 0, 0, false, false, null); michael@0: michael@0: yield shownPromise; michael@0: michael@0: yield checkPlacesContextMenu(menuPopup); michael@0: yield closePopup(menuPopup); michael@0: } michael@0: michael@0: yield closePopup(bookmarksMenuPopup); michael@0: }); michael@0: } michael@0: michael@0: /** michael@0: * Closes a focused popup by simulating pressing the Escape key, michael@0: * and returns a Promise that resolves as soon as the popup is closed. michael@0: * michael@0: * @param aPopup the popup node to close. michael@0: */ michael@0: function closePopup(aPopup) { michael@0: let hiddenPromise = popupHidden(aPopup); michael@0: EventUtils.synthesizeKey("VK_ESCAPE", {}); michael@0: return hiddenPromise; michael@0: } michael@0: michael@0: /** michael@0: * Helper function that checks that the context menu of the michael@0: * bookmark toolbar items chevron popup is correctly hooked up michael@0: * to the controller of a view. michael@0: */ michael@0: function checkBookmarksItemsChevronContextMenu() { michael@0: return Task.spawn(function*() { michael@0: let chevronPopup = document.getElementById("PlacesChevronPopup"); michael@0: let shownPromise = popupShown(chevronPopup); michael@0: let chevron = document.getElementById("PlacesChevron"); michael@0: EventUtils.synthesizeMouseAtCenter(chevron, {}); michael@0: yield shownPromise; michael@0: yield waitForCondition(() => { michael@0: for (let child of chevronPopup.children) { michael@0: if (child.style.visibility != "hidden") michael@0: return true; michael@0: } michael@0: }); michael@0: yield checkPlacesContextMenu(chevronPopup); michael@0: yield closePopup(chevronPopup); michael@0: }); michael@0: } michael@0: michael@0: /** michael@0: * Forces the window to a width that causes the nav-bar to overflow michael@0: * its contents. Returns a Promise that resolves as soon as the michael@0: * overflowable nav-bar is showing its chevron. michael@0: */ michael@0: function overflowEverything() { michael@0: window.resizeTo(kSmallWidth, window.outerHeight); michael@0: return waitForCondition(() => gNavBar.hasAttribute("overflowing")); michael@0: } michael@0: michael@0: /** michael@0: * Returns the window to its original size from the start of the test, michael@0: * and returns a Promise that resolves when the nav-bar is no longer michael@0: * overflowing. michael@0: */ michael@0: function stopOverflowing() { michael@0: window.resizeTo(kOriginalWindowWidth, window.outerHeight); michael@0: return waitForCondition(() => !gNavBar.hasAttribute("overflowing")); michael@0: } michael@0: michael@0: /** michael@0: * Checks that an item with ID aID is overflowing in the nav-bar. michael@0: * michael@0: * @param aID the ID of the node to check for overflowingness. michael@0: */ michael@0: function checkOverflowing(aID) { michael@0: ok(!gNavBar.querySelector("#" + aID), michael@0: "Item with ID " + aID + " should no longer be in the gNavBar"); michael@0: let item = gOverflowList.querySelector("#" + aID); michael@0: ok(item, "Item with ID " + aID + " should be overflowing"); michael@0: is(item.getAttribute("overflowedItem"), "true", michael@0: "Item with ID " + aID + " should have overflowedItem attribute"); michael@0: } michael@0: michael@0: /** michael@0: * Checks that an item with ID aID is not overflowing in the nav-bar. michael@0: * michael@0: * @param aID the ID of hte node to check for non-overflowingness. michael@0: */ michael@0: function checkNotOverflowing(aID) { michael@0: ok(!gOverflowList.querySelector("#" + aID), michael@0: "Item with ID " + aID + " should no longer be overflowing"); michael@0: let item = gNavBar.querySelector("#" + aID); michael@0: ok(item, "Item with ID " + aID + " should be in the nav bar"); michael@0: ok(!item.hasAttribute("overflowedItem"), michael@0: "Item with ID " + aID + " should not have overflowedItem attribute"); michael@0: } michael@0: michael@0: /** michael@0: * Test that overflowing the bookmarks menu button doesn't break the michael@0: * context menus for the Unsorted and Bookmarks Toolbar menu items. michael@0: */ michael@0: add_task(function* testOverflowingBookmarksButtonContextMenu() { michael@0: ok(!gNavBar.hasAttribute("overflowing"), "Should start with a non-overflowing toolbar."); michael@0: ok(CustomizableUI.inDefaultState, "Should start in default state."); michael@0: michael@0: // Open the Unsorted and Bookmarks Toolbar context menus and ensure michael@0: // that they have views attached. michael@0: yield checkSpecialContextMenus(); michael@0: michael@0: yield overflowEverything(); michael@0: checkOverflowing(kBookmarksButton); michael@0: michael@0: yield stopOverflowing(); michael@0: checkNotOverflowing(kBookmarksButton); michael@0: michael@0: yield checkSpecialContextMenus(); michael@0: }); michael@0: michael@0: /** michael@0: * Test that the bookmarks toolbar items context menu still works if moved michael@0: * to the menu from the overflow panel, and then back to the toolbar. michael@0: */ michael@0: add_task(function* testOverflowingBookmarksItemsContextMenu() { michael@0: yield PanelUI.ensureReady(); michael@0: michael@0: let bookmarksToolbarItems = document.getElementById(kBookmarksItems); michael@0: gCustomizeMode.addToToolbar(bookmarksToolbarItems); michael@0: yield checkPlacesContextMenu(bookmarksToolbarItems); michael@0: michael@0: yield overflowEverything(); michael@0: checkOverflowing(kBookmarksItems) michael@0: michael@0: gCustomizeMode.addToPanel(bookmarksToolbarItems); michael@0: michael@0: yield stopOverflowing(); michael@0: michael@0: gCustomizeMode.addToToolbar(bookmarksToolbarItems); michael@0: yield checkPlacesContextMenu(bookmarksToolbarItems); michael@0: }); michael@0: michael@0: /** michael@0: * Test that overflowing the bookmarks toolbar items doesn't cause the michael@0: * context menu in the bookmarks toolbar items chevron to stop working. michael@0: */ michael@0: add_task(function* testOverflowingBookmarksItemsChevronContextMenu() { michael@0: // If it's not already there, let's move the bookmarks toolbar items to michael@0: // the nav-bar. michael@0: let bookmarksToolbarItems = document.getElementById(kBookmarksItems); michael@0: gCustomizeMode.addToToolbar(bookmarksToolbarItems); michael@0: michael@0: // We make the PlacesToolbarItems element be super tiny in order to force michael@0: // the bookmarks toolbar items into overflowing and making the chevron michael@0: // show itself. michael@0: let placesToolbarItems = document.getElementById("PlacesToolbarItems"); michael@0: let placesChevron = document.getElementById("PlacesChevron"); michael@0: placesToolbarItems.style.maxWidth = "10px"; michael@0: yield waitForCondition(() => !placesChevron.collapsed); michael@0: michael@0: yield checkBookmarksItemsChevronContextMenu(); michael@0: michael@0: yield overflowEverything(); michael@0: checkOverflowing(kBookmarksItems); michael@0: michael@0: yield stopOverflowing(); michael@0: checkNotOverflowing(kBookmarksItems); michael@0: michael@0: yield checkBookmarksItemsChevronContextMenu(); michael@0: michael@0: placesToolbarItems.style.removeProperty("max-width"); michael@0: }); michael@0: michael@0: add_task(function* asyncCleanup() { michael@0: window.resizeTo(kOriginalWindowWidth, window.outerHeight); michael@0: yield resetCustomization(); michael@0: });