forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			523 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			523 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* 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/. */
 | 
						|
 | 
						|
"use strict";
 | 
						|
 | 
						|
requestLongerTimeout(2);
 | 
						|
 | 
						|
const { FxAccounts } = ChromeUtils.importESModule(
 | 
						|
  "resource://gre/modules/FxAccounts.sys.mjs"
 | 
						|
);
 | 
						|
let { SyncedTabs } = ChromeUtils.importESModule(
 | 
						|
  "resource://services-sync/SyncedTabs.sys.mjs"
 | 
						|
);
 | 
						|
let { UIState } = ChromeUtils.importESModule(
 | 
						|
  "resource://services-sync/UIState.sys.mjs"
 | 
						|
);
 | 
						|
 | 
						|
ChromeUtils.defineESModuleGetters(this, {
 | 
						|
  UITour: "resource:///modules/UITour.sys.mjs",
 | 
						|
});
 | 
						|
 | 
						|
const DECKINDEX_TABS = 0;
 | 
						|
const DECKINDEX_FETCHING = 1;
 | 
						|
const DECKINDEX_TABSDISABLED = 2;
 | 
						|
const DECKINDEX_NOCLIENTS = 3;
 | 
						|
 | 
						|
const SAMPLE_TAB_URL = "https://example.com/";
 | 
						|
 | 
						|
var initialLocation = gBrowser.currentURI.spec;
 | 
						|
var newTab = null;
 | 
						|
 | 
						|
// A helper to notify there are new tabs. Returns a promise that is resolved
 | 
						|
// once the UI has been updated.
 | 
						|
function updateTabsPanel() {
 | 
						|
  let promiseTabsUpdated = promiseObserverNotified(
 | 
						|
    "synced-tabs-menu:test:tabs-updated"
 | 
						|
  );
 | 
						|
  Services.obs.notifyObservers(null, SyncedTabs.TOPIC_TABS_CHANGED);
 | 
						|
  return promiseTabsUpdated;
 | 
						|
}
 | 
						|
 | 
						|
// This is the mock we use for SyncedTabs.jsm - tests may override various
 | 
						|
// functions.
 | 
						|
let mockedInternal = {
 | 
						|
  get isConfiguredToSyncTabs() {
 | 
						|
    return true;
 | 
						|
  },
 | 
						|
  getTabClients() {
 | 
						|
    return Promise.resolve([]);
 | 
						|
  },
 | 
						|
  syncTabs() {
 | 
						|
    return Promise.resolve();
 | 
						|
  },
 | 
						|
  hasSyncedThisSession: false,
 | 
						|
};
 | 
						|
 | 
						|
add_setup(async function() {
 | 
						|
  const getSignedInUser = FxAccounts.config.getSignedInUser;
 | 
						|
  FxAccounts.config.getSignedInUser = async () =>
 | 
						|
    Promise.resolve({ uid: "uid", email: "foo@bar.com" });
 | 
						|
  Services.prefs.setCharPref(
 | 
						|
    "identity.fxaccounts.remote.root",
 | 
						|
    "https://example.com/"
 | 
						|
  );
 | 
						|
 | 
						|
  let oldInternal = SyncedTabs._internal;
 | 
						|
  SyncedTabs._internal = mockedInternal;
 | 
						|
 | 
						|
  let origNotifyStateUpdated = UIState._internal.notifyStateUpdated;
 | 
						|
  // Sync start-up will interfere with our tests, don't let UIState send UI updates.
 | 
						|
  UIState._internal.notifyStateUpdated = () => {};
 | 
						|
 | 
						|
  // Force gSync initialization
 | 
						|
  gSync.init();
 | 
						|
 | 
						|
  registerCleanupFunction(() => {
 | 
						|
    FxAccounts.config.getSignedInUser = getSignedInUser;
 | 
						|
    Services.prefs.clearUserPref("identity.fxaccounts.remote.root");
 | 
						|
    UIState._internal.notifyStateUpdated = origNotifyStateUpdated;
 | 
						|
    SyncedTabs._internal = oldInternal;
 | 
						|
  });
 | 
						|
});
 | 
						|
 | 
						|
// The test expects the about:preferences#sync page to open in the current tab
 | 
						|
async function openPrefsFromMenuPanel(expectedPanelId, entryPoint) {
 | 
						|
  info("Check Sync button functionality");
 | 
						|
  CustomizableUI.addWidgetToArea(
 | 
						|
    "sync-button",
 | 
						|
    CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
 | 
						|
  );
 | 
						|
 | 
						|
  await waitForOverflowButtonShown();
 | 
						|
 | 
						|
  // check the button's functionality
 | 
						|
  await document.getElementById("nav-bar").overflowable.show();
 | 
						|
 | 
						|
  if (entryPoint == "uitour") {
 | 
						|
    UITour.tourBrowsersByWindow.set(window, new Set());
 | 
						|
    UITour.tourBrowsersByWindow.get(window).add(gBrowser.selectedBrowser);
 | 
						|
  }
 | 
						|
 | 
						|
  let syncButton = document.getElementById("sync-button");
 | 
						|
  ok(syncButton, "The Sync button was added to the Panel Menu");
 | 
						|
 | 
						|
  let tabsUpdatedPromise = promiseObserverNotified(
 | 
						|
    "synced-tabs-menu:test:tabs-updated"
 | 
						|
  );
 | 
						|
  syncButton.click();
 | 
						|
  let syncPanel = document.getElementById("PanelUI-remotetabs");
 | 
						|
  let viewShownPromise = BrowserTestUtils.waitForEvent(syncPanel, "ViewShown");
 | 
						|
  await Promise.all([tabsUpdatedPromise, viewShownPromise]);
 | 
						|
  ok(syncPanel.getAttribute("visible"), "Sync Panel is in view");
 | 
						|
 | 
						|
  // Sync is not configured - verify that state is reflected.
 | 
						|
  let subpanel = document.getElementById(expectedPanelId);
 | 
						|
  ok(!subpanel.hidden, "sync setup element is visible");
 | 
						|
 | 
						|
  // Find and click the "setup" button.
 | 
						|
  let setupButton = subpanel.querySelector(".PanelUI-remotetabs-button");
 | 
						|
  setupButton.click();
 | 
						|
 | 
						|
  await new Promise(resolve => {
 | 
						|
    let handler = async e => {
 | 
						|
      if (
 | 
						|
        e.originalTarget != gBrowser.selectedBrowser.contentDocument ||
 | 
						|
        e.target.location.href == "about:blank"
 | 
						|
      ) {
 | 
						|
        info("Skipping spurious 'load' event for " + e.target.location.href);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      gBrowser.selectedBrowser.removeEventListener("load", handler, true);
 | 
						|
      resolve();
 | 
						|
    };
 | 
						|
    gBrowser.selectedBrowser.addEventListener("load", handler, true);
 | 
						|
  });
 | 
						|
  newTab = gBrowser.selectedTab;
 | 
						|
 | 
						|
  is(
 | 
						|
    gBrowser.currentURI.spec,
 | 
						|
    "about:preferences?entrypoint=" + entryPoint + "#sync",
 | 
						|
    "Firefox Sync preference page opened with `menupanel` entrypoint"
 | 
						|
  );
 | 
						|
  ok(!isOverflowOpen(), "The panel closed");
 | 
						|
 | 
						|
  if (isOverflowOpen()) {
 | 
						|
    await hideOverflow();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
function hideOverflow() {
 | 
						|
  let panelHidePromise = promiseOverflowHidden(window);
 | 
						|
  PanelUI.overflowPanel.hidePopup();
 | 
						|
  return panelHidePromise;
 | 
						|
}
 | 
						|
 | 
						|
async function asyncCleanup() {
 | 
						|
  // reset the panel UI to the default state
 | 
						|
  await resetCustomization();
 | 
						|
  ok(CustomizableUI.inDefaultState, "The panel UI is in default state again.");
 | 
						|
 | 
						|
  // restore the tabs
 | 
						|
  BrowserTestUtils.addTab(gBrowser, initialLocation);
 | 
						|
  gBrowser.removeTab(newTab);
 | 
						|
  UITour.tourBrowsersByWindow.delete(window);
 | 
						|
}
 | 
						|
 | 
						|
// When Sync is not setup.
 | 
						|
add_task(async function() {
 | 
						|
  gSync.updateAllUI({ status: UIState.STATUS_NOT_CONFIGURED });
 | 
						|
  await openPrefsFromMenuPanel("PanelUI-remotetabs-setupsync", "synced-tabs");
 | 
						|
});
 | 
						|
add_task(asyncCleanup);
 | 
						|
 | 
						|
// When an account is connected by Sync is not enabled.
 | 
						|
add_task(async function() {
 | 
						|
  gSync.updateAllUI({ status: UIState.STATUS_SIGNED_IN, syncEnabled: false });
 | 
						|
  await openPrefsFromMenuPanel(
 | 
						|
    "PanelUI-remotetabs-syncdisabled",
 | 
						|
    "synced-tabs"
 | 
						|
  );
 | 
						|
});
 | 
						|
add_task(asyncCleanup);
 | 
						|
 | 
						|
// When Sync is configured in an unverified state.
 | 
						|
add_task(async function() {
 | 
						|
  gSync.updateAllUI({
 | 
						|
    status: UIState.STATUS_NOT_VERIFIED,
 | 
						|
    email: "foo@bar.com",
 | 
						|
  });
 | 
						|
  await openPrefsFromMenuPanel("PanelUI-remotetabs-unverified", "synced-tabs");
 | 
						|
});
 | 
						|
add_task(asyncCleanup);
 | 
						|
 | 
						|
// When Sync is configured in a "needs reauthentication" state.
 | 
						|
add_task(async function() {
 | 
						|
  gSync.updateAllUI({
 | 
						|
    status: UIState.STATUS_LOGIN_FAILED,
 | 
						|
    email: "foo@bar.com",
 | 
						|
  });
 | 
						|
  await openPrefsFromMenuPanel("PanelUI-remotetabs-reauthsync", "synced-tabs");
 | 
						|
});
 | 
						|
 | 
						|
// Test the Connect Another Device button
 | 
						|
add_task(async function() {
 | 
						|
  gSync.updateAllUI({
 | 
						|
    status: UIState.STATUS_SIGNED_IN,
 | 
						|
    syncEnabled: true,
 | 
						|
    email: "foo@bar.com",
 | 
						|
    lastSync: new Date(),
 | 
						|
  });
 | 
						|
 | 
						|
  let button = document.getElementById(
 | 
						|
    "PanelUI-remotetabs-connect-device-button"
 | 
						|
  );
 | 
						|
  ok(button, "found the button");
 | 
						|
 | 
						|
  await document.getElementById("nav-bar").overflowable.show();
 | 
						|
  let expectedUrl =
 | 
						|
    "https://example.com/connect_another_device?context=" +
 | 
						|
    "fx_desktop_v3&entrypoint=synced-tabs&service=sync&uid=uid&email=foo%40bar.com";
 | 
						|
  let promiseTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, expectedUrl);
 | 
						|
  button.click();
 | 
						|
  // the panel should have been closed.
 | 
						|
  ok(!isOverflowOpen(), "click closed the panel");
 | 
						|
  await promiseTabOpened;
 | 
						|
 | 
						|
  gBrowser.removeTab(gBrowser.selectedTab);
 | 
						|
});
 | 
						|
 | 
						|
// Test the "Sync Now" button
 | 
						|
add_task(async function() {
 | 
						|
  gSync.updateAllUI({
 | 
						|
    status: UIState.STATUS_SIGNED_IN,
 | 
						|
    syncEnabled: true,
 | 
						|
    email: "foo@bar.com",
 | 
						|
    lastSync: new Date(),
 | 
						|
  });
 | 
						|
 | 
						|
  await document.getElementById("nav-bar").overflowable.show();
 | 
						|
  let tabsUpdatedPromise = promiseObserverNotified(
 | 
						|
    "synced-tabs-menu:test:tabs-updated"
 | 
						|
  );
 | 
						|
  let syncPanel = document.getElementById("PanelUI-remotetabs");
 | 
						|
  let viewShownPromise = BrowserTestUtils.waitForEvent(syncPanel, "ViewShown");
 | 
						|
  let syncButton = document.getElementById("sync-button");
 | 
						|
  syncButton.click();
 | 
						|
  await Promise.all([tabsUpdatedPromise, viewShownPromise]);
 | 
						|
  ok(syncPanel.getAttribute("visible"), "Sync Panel is in view");
 | 
						|
 | 
						|
  let subpanel = document.getElementById("PanelUI-remotetabs-main");
 | 
						|
  ok(!subpanel.hidden, "main pane is visible");
 | 
						|
  let deck = document.getElementById("PanelUI-remotetabs-deck");
 | 
						|
 | 
						|
  // The widget is still fetching tabs, as we've neutered everything that
 | 
						|
  // provides them
 | 
						|
  is(deck.selectedIndex, DECKINDEX_FETCHING, "first deck entry is visible");
 | 
						|
 | 
						|
  // Tell the widget there are tabs available, but with zero clients.
 | 
						|
  mockedInternal.getTabClients = () => {
 | 
						|
    return Promise.resolve([]);
 | 
						|
  };
 | 
						|
  mockedInternal.hasSyncedThisSession = true;
 | 
						|
  await updateTabsPanel();
 | 
						|
  // The UI should be showing the "no clients" pane.
 | 
						|
  is(
 | 
						|
    deck.selectedIndex,
 | 
						|
    DECKINDEX_NOCLIENTS,
 | 
						|
    "no-clients deck entry is visible"
 | 
						|
  );
 | 
						|
 | 
						|
  // Tell the widget there are tabs available - we have 3 clients, one with no
 | 
						|
  // tabs.
 | 
						|
  mockedInternal.getTabClients = () => {
 | 
						|
    return Promise.resolve([
 | 
						|
      {
 | 
						|
        id: "guid_mobile",
 | 
						|
        type: "client",
 | 
						|
        name: "My Phone",
 | 
						|
        lastModified: 1492201200,
 | 
						|
        tabs: [],
 | 
						|
      },
 | 
						|
      {
 | 
						|
        id: "guid_desktop",
 | 
						|
        type: "client",
 | 
						|
        name: "My Desktop",
 | 
						|
        lastModified: 1492201200,
 | 
						|
        tabs: [
 | 
						|
          {
 | 
						|
            title: "http://example.com/10",
 | 
						|
            lastUsed: 10, // the most recent
 | 
						|
          },
 | 
						|
          {
 | 
						|
            title: "http://example.com/1",
 | 
						|
            lastUsed: 1, // the least recent.
 | 
						|
          },
 | 
						|
          {
 | 
						|
            title: "http://example.com/5",
 | 
						|
            lastUsed: 5,
 | 
						|
          },
 | 
						|
        ],
 | 
						|
      },
 | 
						|
      {
 | 
						|
        id: "guid_second_desktop",
 | 
						|
        name: "My Other Desktop",
 | 
						|
        lastModified: 1492201200,
 | 
						|
        tabs: [
 | 
						|
          {
 | 
						|
            title: "http://example.com/6",
 | 
						|
            lastUsed: 6,
 | 
						|
          },
 | 
						|
        ],
 | 
						|
      },
 | 
						|
    ]);
 | 
						|
  };
 | 
						|
  await updateTabsPanel();
 | 
						|
 | 
						|
  // The UI should be showing tabs!
 | 
						|
  is(deck.selectedIndex, DECKINDEX_TABS, "no-clients deck entry is visible");
 | 
						|
  let tabList = document.getElementById("PanelUI-remotetabs-tabslist");
 | 
						|
  let node = tabList.firstElementChild;
 | 
						|
  // First entry should be the client with the most-recent tab.
 | 
						|
  is(node.nodeName, "vbox");
 | 
						|
  let currentClient = node;
 | 
						|
  node = node.firstElementChild;
 | 
						|
  is(node.getAttribute("itemtype"), "client", "node is a client entry");
 | 
						|
  is(node.textContent, "My Desktop", "correct client");
 | 
						|
  // Next entry is the most-recent tab
 | 
						|
  node = node.nextElementSibling;
 | 
						|
  is(node.getAttribute("itemtype"), "tab", "node is a tab");
 | 
						|
  is(node.getAttribute("label"), "http://example.com/10");
 | 
						|
 | 
						|
  // Next entry is the next-most-recent tab
 | 
						|
  node = node.nextElementSibling;
 | 
						|
  is(node.getAttribute("itemtype"), "tab", "node is a tab");
 | 
						|
  is(node.getAttribute("label"), "http://example.com/5");
 | 
						|
 | 
						|
  // Next entry is the least-recent tab from the first client.
 | 
						|
  node = node.nextElementSibling;
 | 
						|
  is(node.getAttribute("itemtype"), "tab", "node is a tab");
 | 
						|
  is(node.getAttribute("label"), "http://example.com/1");
 | 
						|
  node = node.nextElementSibling;
 | 
						|
  is(node, null, "no more siblings");
 | 
						|
 | 
						|
  // Next is a toolbarseparator between the clients.
 | 
						|
  node = currentClient.nextElementSibling;
 | 
						|
  is(node.nodeName, "toolbarseparator");
 | 
						|
 | 
						|
  // Next is the container for client 2.
 | 
						|
  node = node.nextElementSibling;
 | 
						|
  is(node.nodeName, "vbox");
 | 
						|
  currentClient = node;
 | 
						|
 | 
						|
  // Next is the client with 1 tab.
 | 
						|
  node = node.firstElementChild;
 | 
						|
  is(node.getAttribute("itemtype"), "client", "node is a client entry");
 | 
						|
  is(node.textContent, "My Other Desktop", "correct client");
 | 
						|
  // Its single tab
 | 
						|
  node = node.nextElementSibling;
 | 
						|
  is(node.getAttribute("itemtype"), "tab", "node is a tab");
 | 
						|
  is(node.getAttribute("label"), "http://example.com/6");
 | 
						|
  node = node.nextElementSibling;
 | 
						|
  is(node, null, "no more siblings");
 | 
						|
 | 
						|
  // Next is a toolbarseparator between the clients.
 | 
						|
  node = currentClient.nextElementSibling;
 | 
						|
  is(node.nodeName, "toolbarseparator");
 | 
						|
 | 
						|
  // Next is the container for client 3.
 | 
						|
  node = node.nextElementSibling;
 | 
						|
  is(node.nodeName, "vbox");
 | 
						|
  currentClient = node;
 | 
						|
 | 
						|
  // Next is the client with no tab.
 | 
						|
  node = node.firstElementChild;
 | 
						|
  is(node.getAttribute("itemtype"), "client", "node is a client entry");
 | 
						|
  is(node.textContent, "My Phone", "correct client");
 | 
						|
  // There is a single node saying there's no tabs for the client.
 | 
						|
  node = node.nextElementSibling;
 | 
						|
  is(node.nodeName, "label", "node is a label");
 | 
						|
  is(node.getAttribute("itemtype"), "", "node is neither a tab nor a client");
 | 
						|
 | 
						|
  node = node.nextElementSibling;
 | 
						|
  is(node, null, "no more siblings");
 | 
						|
  is(currentClient.nextElementSibling, null, "no more clients");
 | 
						|
 | 
						|
  // Check accessibility. There should be containers for each client, with an
 | 
						|
  // aria attribute that identifies the client name.
 | 
						|
  let clientContainers = [
 | 
						|
    ...tabList.querySelectorAll("[aria-labelledby]").values(),
 | 
						|
  ];
 | 
						|
  let labelIds = clientContainers.map(container =>
 | 
						|
    container.getAttribute("aria-labelledby")
 | 
						|
  );
 | 
						|
  let labels = labelIds.map(id => document.getElementById(id).textContent);
 | 
						|
  Assert.deepEqual(labels.sort(), [
 | 
						|
    "My Desktop",
 | 
						|
    "My Other Desktop",
 | 
						|
    "My Phone",
 | 
						|
  ]);
 | 
						|
 | 
						|
  let didSync = false;
 | 
						|
  let oldDoSync = gSync.doSync;
 | 
						|
  gSync.doSync = function() {
 | 
						|
    didSync = true;
 | 
						|
    gSync.doSync = oldDoSync;
 | 
						|
  };
 | 
						|
 | 
						|
  let syncNowButton = document.getElementById("PanelUI-remotetabs-syncnow");
 | 
						|
  is(syncNowButton.disabled, false);
 | 
						|
  syncNowButton.click();
 | 
						|
  ok(didSync, "clicking the button called the correct function");
 | 
						|
 | 
						|
  await hideOverflow();
 | 
						|
});
 | 
						|
 | 
						|
// Test the pagination capabilities (Show More/All tabs)
 | 
						|
add_task(async function() {
 | 
						|
  mockedInternal.getTabClients = () => {
 | 
						|
    return Promise.resolve([
 | 
						|
      {
 | 
						|
        id: "guid_desktop",
 | 
						|
        type: "client",
 | 
						|
        name: "My Desktop",
 | 
						|
        lastModified: 1492201200,
 | 
						|
        tabs: (function() {
 | 
						|
          let allTabsDesktop = [];
 | 
						|
          // We choose 77 tabs, because TABS_PER_PAGE is 25, which means
 | 
						|
          // on the second to last page we should have 22 items shown
 | 
						|
          // (because we have to show at least NEXT_PAGE_MIN_TABS=5 tabs on the last page)
 | 
						|
          for (let i = 1; i <= 77; i++) {
 | 
						|
            allTabsDesktop.push({ title: "Tab #" + i, url: SAMPLE_TAB_URL });
 | 
						|
          }
 | 
						|
          return allTabsDesktop;
 | 
						|
        })(),
 | 
						|
      },
 | 
						|
    ]);
 | 
						|
  };
 | 
						|
 | 
						|
  gSync.updateAllUI({
 | 
						|
    status: UIState.STATUS_SIGNED_IN,
 | 
						|
    syncEnabled: true,
 | 
						|
    lastSync: new Date(),
 | 
						|
    email: "foo@bar.com",
 | 
						|
  });
 | 
						|
 | 
						|
  await document.getElementById("nav-bar").overflowable.show();
 | 
						|
  let tabsUpdatedPromise = promiseObserverNotified(
 | 
						|
    "synced-tabs-menu:test:tabs-updated"
 | 
						|
  );
 | 
						|
  let syncPanel = document.getElementById("PanelUI-remotetabs");
 | 
						|
  let viewShownPromise = BrowserTestUtils.waitForEvent(syncPanel, "ViewShown");
 | 
						|
  let syncButton = document.getElementById("sync-button");
 | 
						|
  syncButton.click();
 | 
						|
  await Promise.all([tabsUpdatedPromise, viewShownPromise]);
 | 
						|
 | 
						|
  // Check pre-conditions
 | 
						|
  ok(syncPanel.getAttribute("visible"), "Sync Panel is in view");
 | 
						|
  let subpanel = document.getElementById("PanelUI-remotetabs-main");
 | 
						|
  ok(!subpanel.hidden, "main pane is visible");
 | 
						|
  let deck = document.getElementById("PanelUI-remotetabs-deck");
 | 
						|
  is(deck.selectedIndex, DECKINDEX_TABS, "we should be showing tabs");
 | 
						|
 | 
						|
  function checkTabsPage(tabsShownCount, showMoreLabel) {
 | 
						|
    let tabList = document.getElementById("PanelUI-remotetabs-tabslist");
 | 
						|
    let node = tabList.firstElementChild.firstElementChild;
 | 
						|
    is(node.getAttribute("itemtype"), "client", "node is a client entry");
 | 
						|
    is(node.textContent, "My Desktop", "correct client");
 | 
						|
    for (let i = 0; i < tabsShownCount; i++) {
 | 
						|
      node = node.nextElementSibling;
 | 
						|
      is(node.getAttribute("itemtype"), "tab", "node is a tab");
 | 
						|
      is(
 | 
						|
        node.getAttribute("label"),
 | 
						|
        "Tab #" + (i + 1),
 | 
						|
        "the tab is the correct one"
 | 
						|
      );
 | 
						|
      is(
 | 
						|
        node.getAttribute("targetURI"),
 | 
						|
        SAMPLE_TAB_URL,
 | 
						|
        "url is the correct one"
 | 
						|
      );
 | 
						|
    }
 | 
						|
    let showMoreButton;
 | 
						|
    if (showMoreLabel) {
 | 
						|
      node = showMoreButton = node.nextElementSibling;
 | 
						|
      is(
 | 
						|
        node.getAttribute("itemtype"),
 | 
						|
        "showmorebutton",
 | 
						|
        "node is a show more button"
 | 
						|
      );
 | 
						|
      is(node.getAttribute("label"), showMoreLabel);
 | 
						|
    }
 | 
						|
    node = node.nextElementSibling;
 | 
						|
    is(node, null, "no more entries");
 | 
						|
 | 
						|
    return showMoreButton;
 | 
						|
  }
 | 
						|
 | 
						|
  async function checkCanOpenURL() {
 | 
						|
    let tabList = document.getElementById("PanelUI-remotetabs-tabslist");
 | 
						|
    let node = tabList.firstElementChild.firstElementChild.nextElementSibling;
 | 
						|
    let promiseTabOpened = BrowserTestUtils.waitForLocationChange(
 | 
						|
      gBrowser,
 | 
						|
      SAMPLE_TAB_URL
 | 
						|
    );
 | 
						|
    node.click();
 | 
						|
    await promiseTabOpened;
 | 
						|
  }
 | 
						|
 | 
						|
  let showMoreButton;
 | 
						|
  function clickShowMoreButton() {
 | 
						|
    let promise = promiseObserverNotified("synced-tabs-menu:test:tabs-updated");
 | 
						|
    showMoreButton.click();
 | 
						|
    return promise;
 | 
						|
  }
 | 
						|
 | 
						|
  showMoreButton = checkTabsPage(25, "Show More Tabs");
 | 
						|
  await clickShowMoreButton();
 | 
						|
 | 
						|
  checkTabsPage(77, null);
 | 
						|
  /* calling this will close the overflow menu */
 | 
						|
  await checkCanOpenURL();
 | 
						|
});
 |