summaryrefslogtreecommitdiffstats
path: root/browser/components/places/tests/browser/browser_toolbar_overflow.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/places/tests/browser/browser_toolbar_overflow.js')
-rw-r--r--browser/components/places/tests/browser/browser_toolbar_overflow.js436
1 files changed, 436 insertions, 0 deletions
diff --git a/browser/components/places/tests/browser/browser_toolbar_overflow.js b/browser/components/places/tests/browser/browser_toolbar_overflow.js
new file mode 100644
index 0000000000..03d340b799
--- /dev/null
+++ b/browser/components/places/tests/browser/browser_toolbar_overflow.js
@@ -0,0 +1,436 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Tests the bookmarks toolbar overflow.
+ */
+
+var gToolbar = document.getElementById("PersonalToolbar");
+var gChevron = document.getElementById("PlacesChevron");
+
+const BOOKMARKS_COUNT = 250;
+
+add_setup(async function () {
+ let wasCollapsed = gToolbar.collapsed;
+ await PlacesUtils.bookmarks.eraseEverything();
+
+ // Add bookmarks.
+ await PlacesUtils.bookmarks.insertTree({
+ guid: PlacesUtils.bookmarks.toolbarGuid,
+ children: Array(BOOKMARKS_COUNT)
+ .fill("")
+ .map((_, i) => ({ url: `http://test.places.${i}/` })),
+ });
+
+ // Toggle the bookmarks toolbar so that we start from a stable situation and
+ // are not affected by all bookmarks removal.
+ await toggleToolbar(false);
+ await toggleToolbar(true);
+
+ registerCleanupFunction(async () => {
+ if (wasCollapsed) {
+ await toggleToolbar(false);
+ }
+ await PlacesUtils.bookmarks.eraseEverything();
+ await PlacesUtils.history.clear();
+ });
+});
+
+add_task(async function test_overflow() {
+ // Check that the overflow chevron is visible.
+ Assert.ok(!gChevron.collapsed, "The overflow chevron should be visible");
+ let children = getPlacesChildren();
+ Assert.ok(
+ children.length < BOOKMARKS_COUNT,
+ "Not all the nodes should be built by default"
+ );
+ let visibleNodes = [];
+ for (let node of children) {
+ if (getComputedStyle(node).visibility == "visible") {
+ visibleNodes.push(node);
+ }
+ }
+ Assert.ok(
+ visibleNodes.length < children.length,
+ `The number of visible nodes (${visibleNodes.length}) should be smaller than the number of built nodes (${children.length})`
+ );
+
+ await test_index(
+ "Node at the last visible index",
+ visibleNodes.length - 1,
+ "visible"
+ );
+ await test_index(
+ "Node at the first invisible index",
+ visibleNodes.length,
+ "hidden"
+ );
+ await test_index("First non-built node", children.length, undefined);
+ await test_index("Later non-built node", children.length + 1, undefined);
+
+ await test_move_index(
+ "Move node from last visible to first hidden",
+ visibleNodes.length - 1,
+ visibleNodes.length,
+ "visible",
+ "hidden"
+ );
+ await test_move_index(
+ "Move node from fist visible to last built",
+ 0,
+ children.length - 1,
+ "visible",
+ "hidden"
+ );
+ await test_move_index(
+ "Move node from fist visible to first non built",
+ 0,
+ children.length,
+ "visible",
+ undefined
+ );
+});
+
+add_task(async function test_separator_first() {
+ await toggleToolbar(false);
+ // Check that if a separator is the first node, we still calculate overflow
+ // properly.
+ let bm = await PlacesUtils.bookmarks.insert({
+ parentGuid: PlacesUtils.bookmarks.toolbarGuid,
+ type: PlacesUtils.bookmarks.TYPE_SEPARATOR,
+ index: 0,
+ });
+ await toggleToolbar(true, 2);
+
+ let children = getPlacesChildren();
+ Assert.greater(children.length, 2, "Multiple elements are visible");
+ Assert.equal(
+ children[1]._placesNode.uri,
+ "http://test.places.0/",
+ "Found the first bookmark"
+ );
+ Assert.equal(
+ getComputedStyle(children[1]).visibility,
+ "visible",
+ "The first bookmark is visible"
+ );
+
+ await PlacesUtils.bookmarks.remove(bm);
+});
+
+add_task(async function test_newWindow_noOverflow() {
+ info(
+ "Check toolbar in a new widow when it was already visible and not overflowed"
+ );
+ Assert.ok(!gToolbar.collapsed, "Toolbar is not collapsed in original window");
+ await PlacesUtils.bookmarks.eraseEverything();
+ // Add a single bookmark.
+ await PlacesUtils.bookmarks.insert({
+ parentGuid: PlacesUtils.bookmarks.toolbarGuid,
+ url: "http://toolbar.overflow/",
+ title: "Example",
+ });
+ // Add a favicon for the bookmark.
+ let favicon =
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAA" +
+ "AAAA6fptVAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==";
+ await PlacesTestUtils.addFavicons(
+ new Map([["http://toolbar.overflow/", favicon]])
+ );
+
+ let win = await BrowserTestUtils.openNewBrowserWindow();
+ try {
+ let toolbar = win.document.getElementById("PersonalToolbar");
+ Assert.ok(!toolbar.collapsed, "The toolbar is not collapsed");
+ let content = win.document.getElementById("PlacesToolbarItems");
+ await TestUtils.waitForCondition(() => {
+ return (
+ content.children.length == 1 &&
+ content.children[0].hasAttribute("image")
+ );
+ });
+ let chevron = win.document.getElementById("PlacesChevron");
+ Assert.ok(chevron.collapsed, "The chevron should be collapsed");
+ } finally {
+ await BrowserTestUtils.closeWindow(win);
+ }
+});
+
+async function test_index(desc, index, expected) {
+ info(desc);
+ let children = getPlacesChildren();
+ let originalLen = children.length;
+ let nodeExisted = children.length > index;
+ let previousNodeIsVisible =
+ nodeExisted &&
+ getComputedStyle(children[index - 1]).visibility == "visible";
+ let promise = promiseUpdateVisibility(
+ expected == "visible" || previousNodeIsVisible
+ );
+
+ let bm = await PlacesUtils.bookmarks.insert({
+ parentGuid: PlacesUtils.bookmarks.toolbarGuid,
+ url: "http://test.places.added/",
+ index,
+ });
+ Assert.equal(bm.index, index, "Sanity check the bookmark index");
+ await promise;
+ children = getPlacesChildren();
+
+ if (!expected) {
+ Assert.ok(
+ children.length <= index,
+ "The new node should not have been added"
+ );
+ } else {
+ Assert.equal(
+ children[index]._placesNode.bookmarkGuid,
+ bm.guid,
+ "Found the added bookmark at the expected position"
+ );
+ Assert.equal(
+ getComputedStyle(children[index]).visibility,
+ expected,
+ `The bookmark node should be ${expected}`
+ );
+ }
+ Assert.equal(
+ children.length,
+ originalLen,
+ "Number of built nodes should stay the same"
+ );
+
+ info("Remove the node");
+ promise = promiseUpdateVisibility(expected == "visible");
+
+ await PlacesUtils.bookmarks.remove(bm);
+ await promise;
+ children = getPlacesChildren();
+
+ if (expected && nodeExisted) {
+ Assert.equal(
+ children[index]._placesNode.uri,
+ `http://test.places.${index}/`,
+ "Found the previous bookmark at the expected position"
+ );
+ Assert.equal(
+ getComputedStyle(children[index]).visibility,
+ expected,
+ `The bookmark node should be ${expected}`
+ );
+ }
+ Assert.equal(
+ children.length,
+ originalLen,
+ "Number of built nodes should stay the same"
+ );
+}
+
+async function test_move_index(desc, fromIndex, toIndex, original, expected) {
+ info(desc);
+ let children = getPlacesChildren();
+ let originalLen = children.length;
+ let movedGuid = children[fromIndex]._placesNode.bookmarkGuid;
+ let existingGuid = children[toIndex]
+ ? children[toIndex]._placesNode.bookmarkGuid
+ : null;
+ let existingIndex = fromIndex < toIndex ? toIndex - 1 : toIndex + 1;
+
+ Assert.equal(
+ getComputedStyle(children[fromIndex]).visibility,
+ original,
+ `The bookmark node should be ${original}`
+ );
+ let promise = promiseUpdateVisibility(
+ original == "visible" || expected == "visible"
+ );
+
+ await PlacesUtils.bookmarks.update({
+ guid: movedGuid,
+ index: toIndex,
+ });
+ await promise;
+ children = getPlacesChildren();
+
+ if (!expected) {
+ Assert.ok(
+ children.length <= toIndex,
+ "Node in the new position is not expected"
+ );
+ Assert.ok(
+ children[originalLen - 1],
+ "We should keep number of built nodes consistent"
+ );
+ } else {
+ Assert.equal(
+ children[toIndex]._placesNode.bookmarkGuid,
+ movedGuid,
+ "Found the moved bookmark at the expected position"
+ );
+ Assert.equal(
+ getComputedStyle(children[toIndex]).visibility,
+ expected,
+ `The destination bookmark node should be ${expected}`
+ );
+ }
+ Assert.equal(
+ getComputedStyle(children[fromIndex]).visibility,
+ original,
+ `The origin bookmark node should be ${original}`
+ );
+ if (existingGuid) {
+ Assert.equal(
+ children[existingIndex]._placesNode.bookmarkGuid,
+ existingGuid,
+ "Found the pushed away bookmark at the expected position"
+ );
+ }
+ Assert.equal(
+ children.length,
+ originalLen,
+ "Number of built nodes should stay the same"
+ );
+
+ info("Moving back the node");
+ promise = promiseUpdateVisibility(
+ original == "visible" || expected == "visible"
+ );
+
+ await PlacesUtils.bookmarks.update({
+ guid: movedGuid,
+ index: fromIndex,
+ });
+ await promise;
+ children = getPlacesChildren();
+
+ Assert.equal(
+ children[fromIndex]._placesNode.bookmarkGuid,
+ movedGuid,
+ "Found the moved bookmark at the expected position"
+ );
+ if (expected) {
+ Assert.equal(
+ getComputedStyle(children[toIndex]).visibility,
+ expected,
+ `The bookmark node should be ${expected}`
+ );
+ }
+ Assert.equal(
+ getComputedStyle(children[fromIndex]).visibility,
+ original,
+ `The bookmark node should be ${original}`
+ );
+ if (existingGuid) {
+ Assert.equal(
+ children[toIndex]._placesNode.bookmarkGuid,
+ existingGuid,
+ "Found the pushed away bookmark at the expected position"
+ );
+ }
+ Assert.equal(
+ children.length,
+ originalLen,
+ "Number of built nodes should stay the same"
+ );
+}
+
+add_task(async function test_separator_first() {
+ // Check that if there are only separators, we still show nodes properly.
+ await toggleToolbar(false);
+ await PlacesUtils.bookmarks.eraseEverything();
+ await PlacesUtils.bookmarks.insert({
+ parentGuid: PlacesUtils.bookmarks.toolbarGuid,
+ type: PlacesUtils.bookmarks.TYPE_SEPARATOR,
+ index: 0,
+ });
+ await PlacesUtils.bookmarks.insert({
+ parentGuid: PlacesUtils.bookmarks.toolbarGuid,
+ type: PlacesUtils.bookmarks.TYPE_SEPARATOR,
+ index: 0,
+ });
+ await toggleToolbar(true, 2);
+
+ let children = getPlacesChildren();
+ Assert.equal(children.length, 2, "The expected elements are visible");
+ Assert.equal(
+ getComputedStyle(children[0]).visibility,
+ "visible",
+ "The first bookmark is visible"
+ );
+ Assert.equal(
+ getComputedStyle(children[1]).visibility,
+ "visible",
+ "The second bookmark is visible"
+ );
+
+ await toggleToolbar(false);
+ await PlacesUtils.bookmarks.eraseEverything();
+});
+
+/**
+ * If the passed-in condition is fulfilled, awaits for the toolbar nodes
+ * visibility to have been updated.
+ *
+ * @param {boolean} [condition] Awaits for visibility only if this condition is true.
+ * @returns {Promise} resolved when the condition is not fulfilled or the
+ * visilibily update happened.
+ */
+function promiseUpdateVisibility(condition = true) {
+ if (condition) {
+ return BrowserTestUtils.waitForEvent(
+ gToolbar,
+ "BookmarksToolbarVisibilityUpdated"
+ );
+ }
+ return Promise.resolve();
+}
+
+/**
+ * Returns an array of toolbar children that are Places nodes, ignoring things
+ * like the chevron or other additional buttons.
+ *
+ * @returns {Array} An array of Places element nodes.
+ */
+function getPlacesChildren() {
+ return Array.prototype.filter.call(
+ document.getElementById("PlacesToolbarItems").children,
+ c => c._placesNode?.itemId
+ );
+}
+
+/**
+ * Toggles the toolbar on or off.
+ *
+ * @param {boolean} show Whether to show or hide the toolbar.
+ * @param {number} [expectedMinChildCount] Optional number of Places nodes that
+ * should be visible on the toolbar.
+ */
+async function toggleToolbar(show, expectedMinChildCount = 0) {
+ let promiseReady = Promise.resolve();
+ if (show) {
+ promiseReady = promiseUpdateVisibility();
+ }
+
+ await promiseSetToolbarVisibility(gToolbar, show);
+ await promiseReady;
+
+ if (show) {
+ if (getPlacesChildren().length < expectedMinChildCount) {
+ await new Promise(resolve => {
+ info("Waiting for bookmark elements to appear");
+ let mut = new MutationObserver(mutations => {
+ let children = getPlacesChildren();
+ info(`${children.length} bookmark elements appeared`);
+ if (children.length >= expectedMinChildCount) {
+ resolve();
+ mut.disconnect();
+ }
+ });
+ mut.observe(document.getElementById("PlacesToolbarItems"), {
+ childList: true,
+ });
+ });
+ }
+ }
+}