tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

browser_contextmenu_sendtab.js (11465B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 Services.scriptloader.loadSubScript(
      7  "chrome://mochitests/content/browser/browser/base/content/test/general/head.js",
      8  this
      9 );
     10 Services.scriptloader.loadSubScript(
     11  "chrome://mochitests/content/browser/browser/components/customizableui/test/head.js",
     12  this
     13 );
     14 
     15 const fxaDevices = [
     16  {
     17    id: 1,
     18    name: "Foo",
     19    availableCommands: { "https://identity.mozilla.com/cmd/open-uri": "baz" },
     20    lastAccessTime: Date.now(),
     21  },
     22  {
     23    id: 2,
     24    name: "Bar",
     25    availableCommands: { "https://identity.mozilla.com/cmd/open-uri": "boo" },
     26    lastAccessTime: Date.now() + 60000, // add 30min
     27  },
     28  {
     29    id: 3,
     30    name: "Baz",
     31    clientRecord: "bar",
     32    lastAccessTime: Date.now() + 120000, // add 60min
     33  }, // Legacy send tab target (no availableCommands).
     34  { id: 4, name: "Homer" }, // Incompatible target.
     35 ];
     36 
     37 let [testTab] = gBrowser.visibleTabs;
     38 
     39 function updateTabContextMenu(tab = gBrowser.selectedTab) {
     40  let menu = document.getElementById("tabContextMenu");
     41  var evt = new Event("");
     42  tab.dispatchEvent(evt);
     43  // The TabContextMenu initializes its strings only on a focus or mouseover event.
     44  // Calls focus event on the TabContextMenu early in the test
     45  gBrowser.selectedTab.focus();
     46  menu.openPopup(tab, "end_after", 0, 0, true, false, evt);
     47  is(
     48    window.TabContextMenu.contextTab,
     49    tab,
     50    "TabContextMenu context is the expected tab"
     51  );
     52  menu.hidePopup();
     53 }
     54 
     55 add_setup(async function () {
     56  await SpecialPowers.pushPrefEnv({
     57    set: [
     58      ["browser.urlbar.trustPanel.featureGate", false],
     59      ["test.wait300msAfterTabSwitch", true],
     60    ],
     61  });
     62 
     63  await promiseSyncReady();
     64  await Services.search.init();
     65  // gSync.init() is called in a requestIdleCallback. Force its initialization.
     66  gSync.init();
     67  sinon
     68    .stub(Weave.Service.clientsEngine, "getClientByFxaDeviceId")
     69    .callsFake(fxaDeviceId => {
     70      let target = fxaDevices.find(c => c.id == fxaDeviceId);
     71      return target ? target.clientRecord : null;
     72    });
     73  sinon.stub(Weave.Service.clientsEngine, "getClientType").returns("desktop");
     74  await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:mozilla");
     75  registerCleanupFunction(() => {
     76    gBrowser.removeCurrentTab();
     77  });
     78  is(gBrowser.visibleTabs.length, 2, "there are two visible tabs");
     79 });
     80 
     81 add_task(async function test_sendTabToDevice_callsFlushLogFile() {
     82  const sandbox = setupSendTabMocks({ fxaDevices });
     83  updateTabContextMenu(testTab);
     84  await openTabContextMenu("context_sendTabToDevice");
     85  let promiseObserved = promiseObserver("service:log-manager:flush-log-file");
     86 
     87  await activateMenuItem();
     88  await promiseObserved;
     89  ok(true, "Got flush-log-file observer message");
     90 
     91  await closeConfirmationHint();
     92  sandbox.restore();
     93 });
     94 
     95 async function checkForConfirmationHint(targetId) {
     96  const sandbox = setupSendTabMocks({ fxaDevices });
     97  updateTabContextMenu(testTab);
     98 
     99  await openTabContextMenu("context_sendTabToDevice");
    100  await activateMenuItem();
    101  is(
    102    ConfirmationHint._panel.anchorNode.id,
    103    targetId,
    104    `Hint anchored to ${targetId}`
    105  );
    106  await closeConfirmationHint();
    107  sandbox.restore();
    108 }
    109 
    110 add_task(async function test_sendTabToDevice_showsConfirmationHint_fxa() {
    111  // We need to change the fxastatus from "not_configured" to show the FxA button.
    112  is(
    113    document.documentElement.getAttribute("fxastatus"),
    114    "not_configured",
    115    "FxA button is hidden"
    116  );
    117  document.documentElement.setAttribute("fxastatus", "foo");
    118  await checkForConfirmationHint("fxa-toolbar-menu-button");
    119  document.documentElement.setAttribute("fxastatus", "not_configured");
    120 });
    121 
    122 add_task(
    123  async function test_sendTabToDevice_showsConfirmationHint_onOverflowMenu() {
    124    // We need to change the fxastatus from "not_configured" to show the FxA button.
    125    is(
    126      document.documentElement.getAttribute("fxastatus"),
    127      "not_configured",
    128      "FxA button is hidden"
    129    );
    130    document.documentElement.setAttribute("fxastatus", "foo");
    131 
    132    let navbar = document.getElementById("nav-bar");
    133 
    134    // Resize the window so that the account button is in the overflow menu.
    135    // As of bug 1960002, overflowing the navbar also requires adding extra
    136    // buttons.
    137    let originalWidth = ensureToolbarOverflow(window, false);
    138 
    139    await TestUtils.waitForCondition(() => navbar.hasAttribute("overflowing"));
    140 
    141    await checkForConfirmationHint("PanelUI-menu-button");
    142    document.documentElement.setAttribute("fxastatus", "not_configured");
    143 
    144    unensureToolbarOverflow(window, originalWidth);
    145    await TestUtils.waitForCondition(() => !navbar.hasAttribute("overflowing"));
    146    CustomizableUI.reset();
    147  }
    148 );
    149 
    150 add_task(async function test_sendTabToDevice_showsConfirmationHint_appMenu() {
    151  ensureToolbarOverflow(window);
    152 
    153  // If fxastatus is "not_configured" then the FxA button is hidden, and we
    154  // should use the appMenu.
    155  is(
    156    document.documentElement.getAttribute("fxastatus"),
    157    "not_configured",
    158    "FxA button is hidden"
    159  );
    160  await checkForConfirmationHint("PanelUI-menu-button");
    161 });
    162 
    163 add_task(async function test_tab_contextmenu() {
    164  const sandbox = setupSendTabMocks({ fxaDevices });
    165  let expectation = sandbox
    166    .mock(gSync)
    167    .expects("sendTabToDevice")
    168    .once()
    169    .withExactArgs(
    170      "about:mozilla",
    171      [fxaDevices[1]],
    172      "The Book of Mozilla, 6:27"
    173    )
    174    .returns(true);
    175 
    176  updateTabContextMenu(testTab);
    177  await openTabContextMenu("context_sendTabToDevice");
    178  is(
    179    document.getElementById("context_sendTabToDevice").hidden,
    180    false,
    181    "Send tab to device is shown"
    182  );
    183  is(
    184    document.getElementById("context_sendTabToDeviceSeparator").hidden,
    185    false,
    186    "Send tab to device separator is shown"
    187  );
    188  is(
    189    document.getElementById("context_sendTabToDevice").disabled,
    190    false,
    191    "Send tab to device is enabled"
    192  );
    193 
    194  await activateMenuItem();
    195  await closeConfirmationHint();
    196 
    197  expectation.verify();
    198  sandbox.restore();
    199 });
    200 
    201 add_task(async function test_tab_contextmenu_unconfigured() {
    202  const sandbox = setupSendTabMocks({ state: UIState.STATUS_NOT_CONFIGURED });
    203 
    204  updateTabContextMenu(testTab);
    205  is(
    206    document.getElementById("context_sendTabToDevice").hidden,
    207    true,
    208    "Send tab to device is hidden"
    209  );
    210  is(
    211    document.getElementById("context_sendTabToDeviceSeparator").hidden,
    212    true,
    213    "Send tab to device separator is hidden"
    214  );
    215  is(
    216    document.getElementById("context_sendTabToDevice").disabled,
    217    false,
    218    "Send tab to device is enabled"
    219  );
    220 
    221  sandbox.restore();
    222 });
    223 
    224 add_task(async function test_tab_contextmenu_not_sendable() {
    225  const sandbox = setupSendTabMocks({ fxaDevices, isSendableURI: false });
    226 
    227  updateTabContextMenu(testTab);
    228  is(
    229    document.getElementById("context_sendTabToDevice").hidden,
    230    true,
    231    "Send tab to device is hidden"
    232  );
    233  is(
    234    document.getElementById("context_sendTabToDeviceSeparator").hidden,
    235    true,
    236    "Send tab to device is hidden"
    237  );
    238  is(
    239    document.getElementById("context_sendTabToDevice").disabled,
    240    true,
    241    "Send tab to device is disabled"
    242  );
    243 
    244  sandbox.restore();
    245 });
    246 
    247 add_task(async function test_tab_contextmenu_not_synced_yet() {
    248  const sandbox = setupSendTabMocks({ fxaDevices: null });
    249 
    250  updateTabContextMenu(testTab);
    251  is(
    252    document.getElementById("context_sendTabToDevice").hidden,
    253    true,
    254    "Send tab to device is hidden"
    255  );
    256  is(
    257    document.getElementById("context_sendTabToDeviceSeparator").hidden,
    258    true,
    259    "Send tab to device separator is hidden"
    260  );
    261  is(
    262    document.getElementById("context_sendTabToDevice").disabled,
    263    true,
    264    "Send tab to device is disabled"
    265  );
    266 
    267  sandbox.restore();
    268 });
    269 
    270 add_task(async function test_tab_contextmenu_sync_not_ready_configured() {
    271  const sandbox = setupSendTabMocks({ syncReady: false });
    272 
    273  updateTabContextMenu(testTab);
    274  is(
    275    document.getElementById("context_sendTabToDevice").hidden,
    276    true,
    277    "Send tab to device is hidden"
    278  );
    279  is(
    280    document.getElementById("context_sendTabToDeviceSeparator").hidden,
    281    true,
    282    "Send tab to device is hidden"
    283  );
    284  is(
    285    document.getElementById("context_sendTabToDevice").disabled,
    286    true,
    287    "Send tab to device is disabled"
    288  );
    289 
    290  sandbox.restore();
    291 });
    292 
    293 add_task(async function test_tab_contextmenu_sync_not_ready_other_state() {
    294  const sandbox = setupSendTabMocks({
    295    syncReady: false,
    296    state: UIState.STATUS_NOT_VERIFIED,
    297  });
    298 
    299  updateTabContextMenu(testTab);
    300  is(
    301    document.getElementById("context_sendTabToDevice").hidden,
    302    true,
    303    "Send tab to device is hidden"
    304  );
    305  is(
    306    document.getElementById("context_sendTabToDeviceSeparator").hidden,
    307    true,
    308    "Send tab to device separator is hidden"
    309  );
    310  is(
    311    document.getElementById("context_sendTabToDevice").disabled,
    312    false,
    313    "Send tab to device is enabled"
    314  );
    315 
    316  sandbox.restore();
    317 });
    318 
    319 add_task(async function test_tab_contextmenu_fxa_disabled() {
    320  const getter = sinon.stub(gSync, "FXA_ENABLED").get(() => false);
    321  // Simulate onFxaDisabled() being called on window open.
    322  gSync.onFxaDisabled();
    323 
    324  updateTabContextMenu(testTab);
    325  is(
    326    document.getElementById("context_sendTabToDevice").hidden,
    327    true,
    328    "Send tab to device is hidden"
    329  );
    330  updateTabContextMenu(testTab);
    331  is(
    332    document.getElementById("context_sendTabToDeviceSeparator").hidden,
    333    true,
    334    "Send tab to device separator is hidden"
    335  );
    336 
    337  getter.restore();
    338  [...document.querySelectorAll(".sync-ui-item")].forEach(
    339    e => (e.hidden = false)
    340  );
    341 });
    342 
    343 add_task(async function teardown() {
    344  Weave.Service.clientsEngine.getClientByFxaDeviceId.restore();
    345  Weave.Service.clientsEngine.getClientType.restore();
    346 });
    347 
    348 async function openTabContextMenu(openSubmenuId = null) {
    349  const contextMenu = document.getElementById("tabContextMenu");
    350  is(contextMenu.state, "closed", "checking if popup is closed");
    351 
    352  const awaitPopupShown = BrowserTestUtils.waitForEvent(
    353    contextMenu,
    354    "popupshown"
    355  );
    356  EventUtils.synthesizeMouseAtCenter(gBrowser.selectedTab, {
    357    type: "contextmenu",
    358    button: 2,
    359  });
    360  await awaitPopupShown;
    361 
    362  if (openSubmenuId) {
    363    const menuPopup = document.getElementById(openSubmenuId).menupopup;
    364    const menuPopupPromise = BrowserTestUtils.waitForEvent(
    365      menuPopup,
    366      "popupshown"
    367    );
    368    menuPopup.openPopup();
    369    await menuPopupPromise;
    370  }
    371 }
    372 
    373 function promiseObserver(topic) {
    374  return new Promise(resolve => {
    375    let obs = (aSubject, aTopic) => {
    376      Services.obs.removeObserver(obs, aTopic);
    377      resolve(aSubject);
    378    };
    379    Services.obs.addObserver(obs, topic);
    380  });
    381 }
    382 
    383 function waitForConfirmationHint() {
    384  return BrowserTestUtils.waitForEvent(ConfirmationHint._panel, "popuphidden");
    385 }
    386 
    387 async function activateMenuItem() {
    388  let popupHidden = BrowserTestUtils.waitForEvent(
    389    document.getElementById("tabContextMenu"),
    390    "popuphidden"
    391  );
    392  let hintShown = BrowserTestUtils.waitForEvent(
    393    ConfirmationHint._panel,
    394    "popupshown"
    395  );
    396  let menuitem = document
    397    .getElementById("context_sendTabToDevicePopupMenu")
    398    .querySelector("menuitem");
    399  menuitem.closest("menupopup").activateItem(menuitem);
    400  await popupHidden;
    401  await hintShown;
    402 }
    403 
    404 async function closeConfirmationHint() {
    405  let hintHidden = BrowserTestUtils.waitForEvent(
    406    ConfirmationHint._panel,
    407    "popuphidden"
    408  );
    409  ConfirmationHint._panel.hidePopup();
    410  await hintHidden;
    411 }