tor-browser

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

browser_history_recently_closed.js (28101B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 const { SessionStoreTestUtils } = ChromeUtils.importESModule(
      8  "resource://testing-common/SessionStoreTestUtils.sys.mjs"
      9 );
     10 const { TabStateFlusher } = ChromeUtils.importESModule(
     11  "resource:///modules/sessionstore/TabStateFlusher.sys.mjs"
     12 );
     13 const triggeringPrincipal_base64 = E10SUtils.SERIALIZED_SYSTEMPRINCIPAL;
     14 
     15 SessionStoreTestUtils.init(this, window);
     16 
     17 const TEST_PATH = getRootDirectory(gTestPath).replace(
     18  "chrome://mochitests/content",
     19  "https://example.com"
     20 );
     21 
     22 let panelMenuWidgetAdded = false;
     23 function prepareHistoryPanel() {
     24  if (panelMenuWidgetAdded) {
     25    return;
     26  }
     27  CustomizableUI.addWidgetToArea(
     28    "history-panelmenu",
     29    CustomizableUI.AREA_FIXED_OVERFLOW_PANEL
     30  );
     31  registerCleanupFunction(() => CustomizableUI.reset());
     32 }
     33 
     34 async function openRecentlyClosedTabsMenu(doc = window.document) {
     35  prepareHistoryPanel();
     36  await openHistoryPanel(doc);
     37 
     38  let recentlyClosedTabs = doc.getElementById("appMenuRecentlyClosedTabs");
     39  Assert.ok(
     40    !recentlyClosedTabs.getAttribute("disabled"),
     41    "Recently closed tabs button enabled"
     42  );
     43  let closeTabsPanel = doc.getElementById("appMenu-library-recentlyClosedTabs");
     44  let panelView = closeTabsPanel && PanelView.forNode(closeTabsPanel);
     45  if (!panelView?.active) {
     46    recentlyClosedTabs.click();
     47    closeTabsPanel = doc.getElementById("appMenu-library-recentlyClosedTabs");
     48    await BrowserTestUtils.waitForEvent(closeTabsPanel, "ViewShown");
     49    ok(
     50      PanelView.forNode(closeTabsPanel)?.active,
     51      "Opened 'Recently closed tabs' panel"
     52    );
     53  }
     54 
     55  return closeTabsPanel;
     56 }
     57 
     58 function makeTabState(url) {
     59  return {
     60    entries: [{ url, triggeringPrincipal_base64 }],
     61  };
     62 }
     63 
     64 function makeClosedTabState(url, { groupId, closedInTabGroup = false } = {}) {
     65  return {
     66    title: url,
     67    closedInTabGroupId: closedInTabGroup ? groupId : null,
     68    state: {
     69      entries: [
     70        {
     71          url,
     72          triggeringPrincipal_base64,
     73        },
     74      ],
     75      groupId,
     76    },
     77  };
     78 }
     79 
     80 function resetClosedTabsAndWindows() {
     81  // Clear the lists of closed windows and tabs.
     82  Services.obs.notifyObservers(null, "browser:purge-session-history");
     83  is(SessionStore.getClosedWindowCount(), 0, "Expect 0 closed windows");
     84  for (const win of BrowserWindowTracker.orderedWindows) {
     85    is(
     86      SessionStore.getClosedTabCountForWindow(win),
     87      0,
     88      "Expect 0 closed tabs for this window"
     89    );
     90  }
     91 }
     92 
     93 registerCleanupFunction(async () => {
     94  await resetClosedTabsAndWindows();
     95 });
     96 
     97 add_task(async function testRecentlyClosedDisabled() {
     98  info("Check history recently closed tabs/windows section");
     99 
    100  prepareHistoryPanel();
    101  // We need to make sure the history is cleared before starting the test
    102  await Sanitizer.sanitize(["history"]);
    103 
    104  await openHistoryPanel();
    105 
    106  let recentlyClosedTabs = document.getElementById("appMenuRecentlyClosedTabs");
    107  let recentlyClosedWindows = document.getElementById(
    108    "appMenuRecentlyClosedWindows"
    109  );
    110 
    111  // Wait for the disabled attribute to change, as we receive
    112  // the "viewshown" event before this changes
    113  await BrowserTestUtils.waitForCondition(
    114    () => recentlyClosedTabs.hasAttribute("disabled"),
    115    "Waiting for button to become disabled"
    116  );
    117  Assert.ok(
    118    recentlyClosedTabs.hasAttribute("disabled"),
    119    "Recently closed tabs button disabled"
    120  );
    121  Assert.ok(
    122    recentlyClosedWindows.hasAttribute("disabled"),
    123    "Recently closed windows button disabled"
    124  );
    125 
    126  await hideHistoryPanel();
    127 
    128  gBrowser.selectedTab.focus();
    129  await SessionStoreTestUtils.openAndCloseTab(
    130    window,
    131    TEST_PATH + "dummy_history_item.html"
    132  );
    133 
    134  await openHistoryPanel();
    135 
    136  await BrowserTestUtils.waitForCondition(
    137    () => !recentlyClosedTabs.hasAttribute("disabled"),
    138    "Waiting for button to be enabled"
    139  );
    140  Assert.ok(
    141    !recentlyClosedTabs.hasAttribute("disabled"),
    142    "Recently closed tabs is available"
    143  );
    144  Assert.ok(
    145    recentlyClosedWindows.hasAttribute("disabled"),
    146    "Recently closed windows button disabled"
    147  );
    148 
    149  await hideHistoryPanel();
    150 
    151  let newWin = await BrowserTestUtils.openNewBrowserWindow();
    152  let loadedPromise = BrowserTestUtils.browserLoaded(
    153    newWin.gBrowser.selectedBrowser
    154  );
    155  BrowserTestUtils.startLoadingURIString(
    156    newWin.gBrowser.selectedBrowser,
    157    "about:mozilla"
    158  );
    159  await loadedPromise;
    160  await BrowserTestUtils.closeWindow(newWin);
    161 
    162  await openHistoryPanel();
    163 
    164  await BrowserTestUtils.waitForCondition(
    165    () => !recentlyClosedWindows.hasAttribute("disabled"),
    166    "Waiting for button to be enabled"
    167  );
    168  Assert.ok(
    169    !recentlyClosedTabs.hasAttribute("disabled"),
    170    "Recently closed tabs is available"
    171  );
    172  Assert.ok(
    173    !recentlyClosedWindows.hasAttribute("disabled"),
    174    "Recently closed windows is available"
    175  );
    176 
    177  await hideHistoryPanel();
    178 });
    179 
    180 add_task(async function testRecentlyClosedTabsDisabledPersists() {
    181  info("Check history recently closed tabs/windows section");
    182 
    183  prepareHistoryPanel();
    184 
    185  // We need to make sure the history is cleared before starting the test
    186  await Sanitizer.sanitize(["history"]);
    187 
    188  await openHistoryPanel();
    189 
    190  let recentlyClosedTabs = document.getElementById("appMenuRecentlyClosedTabs");
    191  Assert.ok(
    192    recentlyClosedTabs.hasAttribute("disabled"),
    193    "Recently closed tabs button disabled"
    194  );
    195 
    196  await hideHistoryPanel();
    197 
    198  let newWin = await BrowserTestUtils.openNewBrowserWindow();
    199 
    200  await openHistoryPanel(newWin.document);
    201  recentlyClosedTabs = newWin.document.getElementById(
    202    "appMenuRecentlyClosedTabs"
    203  );
    204  Assert.ok(
    205    recentlyClosedTabs.hasAttribute("disabled"),
    206    "Recently closed tabs is disabled"
    207  );
    208 
    209  // We close the window without hiding the panel first, which used to interfere
    210  // with populating the view subsequently.
    211  await BrowserTestUtils.closeWindow(newWin);
    212 
    213  newWin = await BrowserTestUtils.openNewBrowserWindow();
    214  await openHistoryPanel(newWin.document);
    215  recentlyClosedTabs = newWin.document.getElementById(
    216    "appMenuRecentlyClosedTabs"
    217  );
    218  Assert.ok(
    219    recentlyClosedTabs.hasAttribute("disabled"),
    220    "Recently closed tabs is disabled"
    221  );
    222  await hideHistoryPanel(newWin.document);
    223  await BrowserTestUtils.closeWindow(newWin);
    224 });
    225 
    226 add_task(async function testRecentlyClosedRestoreAllTabs() {
    227  // We need to make sure the history is cleared before starting the test
    228  await Sanitizer.sanitize(["history"]);
    229  await resetClosedTabsAndWindows();
    230  const initialTabCount = gBrowser.visibleTabs.length;
    231 
    232  const closedTabUrls = [
    233    "about:robots",
    234    "https://example.com/",
    235    "https://example.org/",
    236  ];
    237 
    238  const closedTabGroupInOpenWindowUrls = ["about:logo", "about:logo"];
    239  const closedTabGroupInOpenWindowId = "1234567890-1";
    240 
    241  const closedTabGroupInClosedWindowUrls = ["about:robots", "about:robots"];
    242  const closedTabGroupInClosedWindowId = "1234567890-2";
    243 
    244  await SessionStoreTestUtils.promiseBrowserState({
    245    windows: [
    246      {
    247        tabs: [makeTabState("about:mozilla")],
    248        _closedTabs: closedTabUrls.map(makeClosedTabState),
    249        closedGroups: [
    250          {
    251            collapsed: false,
    252            color: "blue",
    253            id: closedTabGroupInOpenWindowId,
    254            name: "closed-in-open-window",
    255            tabs: closedTabGroupInOpenWindowUrls.map(url =>
    256              makeClosedTabState(url, { groupId: closedTabGroupInOpenWindowId })
    257            ),
    258          },
    259        ],
    260      },
    261    ],
    262    _closedWindows: [
    263      {
    264        tabs: [makeTabState("about:mozilla")],
    265        _closedTabs: [],
    266        closedGroups: [
    267          {
    268            collapsed: false,
    269            color: "red",
    270            id: closedTabGroupInClosedWindowId,
    271            name: "closed-in-closed-window",
    272            tabs: closedTabGroupInClosedWindowUrls.map(url =>
    273              makeClosedTabState(url, {
    274                groupId: closedTabGroupInClosedWindowId,
    275              })
    276            ),
    277          },
    278        ],
    279      },
    280    ],
    281  });
    282 
    283  is(gBrowser.visibleTabs.length, 1, "We start with one tab open");
    284  // Open the "Recently closed tabs" panel.
    285  let closeTabsPanel = await openRecentlyClosedTabsMenu();
    286 
    287  // Click the first toolbar button in the panel.
    288  let toolbarButton = closeTabsPanel.querySelector(
    289    ".panel-subview-body toolbarbutton"
    290  );
    291  let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
    292  EventUtils.sendMouseEvent({ type: "click" }, toolbarButton, window);
    293 
    294  info(
    295    "We should reopen the first of closedTabUrls: " +
    296      JSON.stringify(closedTabUrls)
    297  );
    298  let reopenedTab = await newTabPromise;
    299  is(
    300    reopenedTab.linkedBrowser.currentURI.spec,
    301    closedTabUrls[0],
    302    "Opened the first URL"
    303  );
    304  info(`restored tab, total open tabs: ${gBrowser.tabs.length}`);
    305 
    306  info("waiting for closeTab");
    307  await SessionStoreTestUtils.closeTab(reopenedTab);
    308 
    309  await openRecentlyClosedTabsMenu();
    310  let restoreAllItem = closeTabsPanel.querySelector(".restoreallitem");
    311  ok(
    312    restoreAllItem && !restoreAllItem.hidden,
    313    "Restore all menu item is not hidden"
    314  );
    315 
    316  // Click the restore-all toolbar button in the panel.
    317  EventUtils.sendMouseEvent({ type: "click" }, restoreAllItem, window);
    318 
    319  info("waiting for restored tabs");
    320  await BrowserTestUtils.waitForCondition(
    321    () => SessionStore.getClosedTabCount() === 0,
    322    "Waiting for all the closed tabs to be opened"
    323  );
    324 
    325  is(
    326    gBrowser.tabs.length,
    327    initialTabCount +
    328      closedTabUrls.length +
    329      closedTabGroupInOpenWindowUrls.length +
    330      closedTabGroupInClosedWindowUrls.length,
    331    "The expected number of closed tabs were restored"
    332  );
    333  is(
    334    gBrowser.tabGroups[0].id,
    335    closedTabGroupInOpenWindowId,
    336    "Closed tab group in open window was restored"
    337  );
    338  closedTabGroupInOpenWindowUrls.forEach((expectedUrl, index) => {
    339    is(
    340      gBrowser.tabGroups[0].tabs[index].linkedBrowser.currentURI.spec,
    341      expectedUrl,
    342      `Closed tab group in open window tab #${index} has correct URL`
    343    );
    344  });
    345  is(
    346    gBrowser.tabGroups[1].id,
    347    closedTabGroupInClosedWindowId,
    348    "Closed tab group in closed window was restored"
    349  );
    350  closedTabGroupInClosedWindowUrls.forEach((expectedUrl, index) => {
    351    is(
    352      gBrowser.tabGroups[1].tabs[index].linkedBrowser.currentURI.spec,
    353      expectedUrl,
    354      `Closed tab group in closed window tab #${index} has correct URL`
    355    );
    356  });
    357 
    358  // clean up extra tabs
    359  while (gBrowser.tabs.length > 1) {
    360    BrowserTestUtils.removeTab(gBrowser.tabs.at(-1));
    361  }
    362 });
    363 
    364 add_task(async function testRecentlyClosedWindows() {
    365  // We need to make sure the history is cleared before starting the test
    366  await Sanitizer.sanitize(["history"]);
    367  await resetClosedTabsAndWindows();
    368 
    369  // Open and close a new window.
    370  let newWin = await BrowserTestUtils.openNewBrowserWindow();
    371  let loadedPromise = BrowserTestUtils.browserLoaded(
    372    newWin.gBrowser.selectedBrowser
    373  );
    374  BrowserTestUtils.startLoadingURIString(
    375    newWin.gBrowser.selectedBrowser,
    376    "https://example.com"
    377  );
    378  await loadedPromise;
    379  let closedObjectsChangePromise = TestUtils.topicObserved(
    380    "sessionstore-closed-objects-changed"
    381  );
    382  await BrowserTestUtils.closeWindow(newWin);
    383  await closedObjectsChangePromise;
    384 
    385  prepareHistoryPanel();
    386  await openHistoryPanel();
    387 
    388  // Open the "Recently closed windows" panel.
    389  document.getElementById("appMenuRecentlyClosedWindows").click();
    390 
    391  let winPanel = document.getElementById(
    392    "appMenu-library-recentlyClosedWindows"
    393  );
    394  await BrowserTestUtils.waitForEvent(winPanel, "ViewShown");
    395  ok(true, "Opened 'Recently closed windows' panel");
    396 
    397  // Click the first toolbar button in the panel.
    398  let panelBody = winPanel.querySelector(".panel-subview-body");
    399  let toolbarButton = panelBody.querySelector("toolbarbutton");
    400  let newWindowPromise = BrowserTestUtils.waitForNewWindow({
    401    url: "https://example.com/",
    402  });
    403  closedObjectsChangePromise = TestUtils.topicObserved(
    404    "sessionstore-closed-objects-changed"
    405  );
    406  EventUtils.sendMouseEvent({ type: "click" }, toolbarButton, window);
    407 
    408  newWin = await newWindowPromise;
    409  await closedObjectsChangePromise;
    410  is(gBrowser.tabs.length, 1, "Did not open new tabs");
    411 
    412  await BrowserTestUtils.closeWindow(newWin);
    413 });
    414 
    415 add_task(async function testRecentlyClosedTabsFromClosedWindows() {
    416  await resetClosedTabsAndWindows();
    417  const closedTabUrls = [
    418    "about:robots",
    419    "https://example.com/",
    420    "https://example.org/",
    421  ];
    422  const closedWindowState = {
    423    tabs: [
    424      {
    425        entries: [{ url: "about:mozilla", triggeringPrincipal_base64 }],
    426      },
    427    ],
    428    closedGroups: [],
    429    _closedTabs: closedTabUrls.map(url => {
    430      return {
    431        title: url,
    432        state: {
    433          entries: [
    434            {
    435              url,
    436              triggeringPrincipal_base64,
    437            },
    438          ],
    439        },
    440      };
    441    }),
    442  };
    443  await SessionStoreTestUtils.promiseBrowserState({
    444    windows: [
    445      {
    446        tabs: [
    447          {
    448            entries: [{ url: "about:mozilla", triggeringPrincipal_base64 }],
    449          },
    450        ],
    451      },
    452    ],
    453    _closedWindows: [closedWindowState],
    454  });
    455  Assert.equal(
    456    SessionStore.getClosedTabCountFromClosedWindows(),
    457    closedTabUrls.length,
    458    "Sanity check number of closed tabs from closed windows"
    459  );
    460 
    461  prepareHistoryPanel();
    462  let closeTabsPanel = await openRecentlyClosedTabsMenu();
    463  // make sure we can actually restore one of these closed tabs
    464  const closedTabItems = closeTabsPanel.querySelectorAll(
    465    "toolbarbutton[targetURI]"
    466  );
    467  Assert.equal(
    468    closedTabItems.length,
    469    closedTabUrls.length,
    470    "We have expected number of closed tab items"
    471  );
    472 
    473  const newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
    474  const closedObjectsChangePromise = TestUtils.topicObserved(
    475    "sessionstore-closed-objects-changed"
    476  );
    477  EventUtils.sendMouseEvent({ type: "click" }, closedTabItems[0], window);
    478  await newTabPromise;
    479  await closedObjectsChangePromise;
    480 
    481  // flip the pref so none of the closed tabs from closed window are included
    482  await SpecialPowers.pushPrefEnv({
    483    set: [["browser.sessionstore.closedTabsFromClosedWindows", false]],
    484  });
    485  await openHistoryPanel();
    486 
    487  // verify the recently-closed-tabs menu item is disabled
    488  let recentlyClosedTabsItem = document.getElementById(
    489    "appMenuRecentlyClosedTabs"
    490  );
    491  Assert.ok(
    492    recentlyClosedTabsItem.hasAttribute("disabled"),
    493    "Recently closed tabs button is now disabled"
    494  );
    495  await hideHistoryPanel();
    496 
    497  SpecialPowers.popPrefEnv();
    498  while (gBrowser.tabs.length > 1) {
    499    await SessionStoreTestUtils.closeTab(
    500      gBrowser.tabs[gBrowser.tabs.length - 1]
    501    );
    502  }
    503 });
    504 
    505 add_task(async function testRecentlyClosedTabGroupsSingleTab() {
    506  // We need to make sure the history is cleared before starting the test
    507  await Sanitizer.sanitize(["history"]);
    508  await resetClosedTabsAndWindows();
    509  prepareHistoryPanel();
    510 
    511  is(gBrowser.visibleTabs.length, 1, "We start with one tab already open");
    512 
    513  let aboutMozillaTab = BrowserTestUtils.addTab(gBrowser, "about:mozilla");
    514  let aboutLogoTab = BrowserTestUtils.addTab(gBrowser, "about:logo");
    515  let mozillaTabGroup = gBrowser.addTabGroup([aboutMozillaTab, aboutLogoTab], {
    516    color: "red",
    517    label: "mozilla stuff",
    518  });
    519  const mozillaTabGroupId = mozillaTabGroup.id;
    520  const mozillaTabGroupName = mozillaTabGroup.label;
    521  let aboutRobotsTab = BrowserTestUtils.addTab(gBrowser, "about:robots");
    522 
    523  info("load all of the tabs");
    524  await Promise.all(
    525    [aboutMozillaTab, aboutLogoTab, aboutRobotsTab].map(async t => {
    526      await BrowserTestUtils.browserLoaded(t.linkedBrowser);
    527      await TabStateFlusher.flush(t.linkedBrowser);
    528    })
    529  );
    530 
    531  info("close the tab group and wait for it to be removed");
    532  let removePromise = BrowserTestUtils.waitForEvent(
    533    mozillaTabGroup,
    534    "TabGroupRemoved"
    535  );
    536  gBrowser.removeTabGroup(mozillaTabGroup);
    537  await removePromise;
    538 
    539  is(
    540    gBrowser.visibleTabs.length,
    541    2,
    542    "The tab from before the test plus about:robots should still be open"
    543  );
    544  info("Open the 'Recently closed tabs' panel.");
    545  let closeTabsPanel = await openRecentlyClosedTabsMenu();
    546 
    547  // Click the tab group button in the panel.
    548  let tabGroupToolbarButton = closeTabsPanel.querySelector(
    549    `.panel-subview-body toolbarbutton[label="${mozillaTabGroupName}"]`
    550  );
    551  ok(tabGroupToolbarButton, "should find the tab group toolbar button");
    552 
    553  let tabGroupPanelview = document.getElementById(
    554    `closed-tabs-tab-group-${mozillaTabGroupId}`
    555  );
    556  ok(tabGroupPanelview, "should find the tab group panelview");
    557 
    558  EventUtils.sendMouseEvent({ type: "click" }, tabGroupToolbarButton, window);
    559  await BrowserTestUtils.waitForEvent(tabGroupPanelview, "ViewShown");
    560 
    561  info("restore the first tab from the closed tab group");
    562  let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
    563  let tabToolbarButton = tabGroupPanelview.querySelector(
    564    ".panel-subview-body toolbarbutton"
    565  );
    566  ok(tabToolbarButton, "should find at least one tab to restore");
    567  let tabTitle = tabToolbarButton.label;
    568  EventUtils.sendMouseEvent({ type: "click" }, tabToolbarButton, window);
    569 
    570  let reopenedTab = await newTabPromise;
    571  is(reopenedTab.label, tabTitle, "Opened the first URL");
    572  info(`restored tab, total open tabs: ${gBrowser.tabs.length}`);
    573 
    574  // clean up extra tabs
    575  while (gBrowser.tabs.length > 1) {
    576    BrowserTestUtils.removeTab(gBrowser.tabs.at(-1));
    577  }
    578 });
    579 
    580 add_task(async function testRecentlyClosedTabGroupOpensFromAnyWindow() {
    581  // We need to make sure the history is cleared before starting the test
    582  await Sanitizer.sanitize(["history"]);
    583  await resetClosedTabsAndWindows();
    584  prepareHistoryPanel();
    585 
    586  is(gBrowser.visibleTabs.length, 1, "We start with one tab already open");
    587 
    588  let groupedTab = BrowserTestUtils.addTab(gBrowser, "https://example.com");
    589  await BrowserTestUtils.browserLoaded(groupedTab.linkedBrowser);
    590  await TabStateFlusher.flush(groupedTab.linkedBrowser);
    591  let tabGroup = gBrowser.addTabGroup([groupedTab], { label: "Some group" });
    592  const tabGroupId = tabGroup.id;
    593  const tabGroupLabel = tabGroup.label;
    594 
    595  info("close the tab group and wait for it to be removed");
    596  let removePromise = BrowserTestUtils.waitForEvent(
    597    tabGroup,
    598    "TabGroupRemoved"
    599  );
    600  gBrowser.removeTabGroup(tabGroup);
    601  await removePromise;
    602 
    603  let newWin = await BrowserTestUtils.openNewBrowserWindow();
    604  let closeTabsPanel = await openRecentlyClosedTabsMenu(newWin.document);
    605 
    606  // Click the tab group button in the panel.
    607  let tabGroupToolbarButton = closeTabsPanel.querySelector(
    608    `.panel-subview-body toolbarbutton[label="${tabGroupLabel}"]`
    609  );
    610  ok(tabGroupToolbarButton, "should find the tab group toolbar button");
    611 
    612  let tabGroupPanelview = newWin.document.getElementById(
    613    `closed-tabs-tab-group-${tabGroupId}`
    614  );
    615  ok(tabGroupPanelview, "should find the tab group panelview");
    616 
    617  EventUtils.sendMouseEvent({ type: "click" }, tabGroupToolbarButton, window);
    618  await BrowserTestUtils.waitForEvent(tabGroupPanelview, "ViewShown");
    619 
    620  let tabToolbarButton = tabGroupPanelview.querySelector(
    621    "toolbarbutton.reopentabgroupitem"
    622  );
    623  let tabGroupRestored = BrowserTestUtils.waitForEvent(
    624    newWin.gBrowser.tabContainer,
    625    "SSTabRestored"
    626  );
    627  EventUtils.sendMouseEvent({ type: "click" }, tabToolbarButton, window);
    628  await tabGroupRestored;
    629 
    630  is(
    631    newWin.gBrowser.tabGroups.length,
    632    1,
    633    "Tab group added to new window tab strip"
    634  );
    635  is(
    636    newWin.gBrowser.tabGroups[0].label,
    637    tabGroupLabel,
    638    "Tab group label is the same as it was before restore"
    639  );
    640 
    641  await BrowserTestUtils.closeWindow(newWin);
    642 });
    643 
    644 add_task(async function testRecentlyClosedTabsFromManyWindows() {
    645  // Ensures that bug1943850 has a proper resolution.
    646  info(
    647    "Tabs must be indexed by individual window, even when multiple windows are open"
    648  );
    649 
    650  await resetClosedTabsAndWindows();
    651  const ORIG_STATE = SessionStore.getBrowserState();
    652 
    653  await SessionStoreTestUtils.promiseBrowserState({
    654    windows: [
    655      {
    656        tabs: [makeTabState("about:mozilla")],
    657        _closedTabs: [
    658          makeClosedTabState("about:mozilla"),
    659          makeClosedTabState("about:mozilla"),
    660        ],
    661      },
    662      {
    663        tabs: [makeTabState("about:mozilla")],
    664        _closedTabs: [makeClosedTabState("about:robots")],
    665      },
    666    ],
    667  });
    668 
    669  Assert.equal(
    670    SessionStore.getClosedTabCount(),
    671    3,
    672    "Sanity check number of closed tabs from closed windows"
    673  );
    674 
    675  prepareHistoryPanel();
    676  let closeTabsPanel = await openRecentlyClosedTabsMenu();
    677 
    678  info("make sure we can actually restore one of these closed tabs");
    679  const closedTabItems = closeTabsPanel.querySelectorAll(
    680    "toolbarbutton[targetURI]"
    681  );
    682  Assert.equal(
    683    closedTabItems.length,
    684    3,
    685    "We have expected number of closed tab items"
    686  );
    687 
    688  const newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
    689  const closedObjectsChangePromise = TestUtils.topicObserved(
    690    "sessionstore-closed-objects-changed"
    691  );
    692  EventUtils.sendMouseEvent({ type: "click" }, closedTabItems[2], window);
    693  await newTabPromise;
    694  await closedObjectsChangePromise;
    695 
    696  Assert.equal(
    697    gBrowser.tabs[1].linkedBrowser.currentURI.spec,
    698    "about:robots",
    699    "Closed tab from the second window is opened"
    700  );
    701 
    702  await SessionStoreTestUtils.promiseBrowserState(ORIG_STATE);
    703 });
    704 
    705 add_task(async function testTabsFromGroupClosedBeforeGroupDeleted() {
    706  // Ensures that bug1945111 has a proper resolution.
    707  info(
    708    "Tabs that were closed from within a tab group should appear in history menus as standalone tabs, even if the tab group is later deleted"
    709  );
    710 
    711  await resetClosedTabsAndWindows();
    712  const ORIG_STATE = SessionStore.getBrowserState();
    713  const GROUP_ID = "1234567890-1";
    714 
    715  await SessionStoreTestUtils.promiseBrowserState({
    716    windows: [
    717      {
    718        tabs: [makeTabState("about:blank")],
    719        _closedTabs: [
    720          makeClosedTabState("about:mozilla", { groupId: GROUP_ID }),
    721        ],
    722        closedGroups: [
    723          {
    724            id: GROUP_ID,
    725            color: "blue",
    726            name: "tab-group",
    727            tabs: [
    728              makeClosedTabState("about:mozilla", {
    729                groupId: GROUP_ID,
    730                closedInTabGroup: true,
    731              }),
    732              makeClosedTabState("about:mozilla", {
    733                groupId: GROUP_ID,
    734                closedInTabGroup: true,
    735              }),
    736              makeClosedTabState("about:mozilla", {
    737                groupId: GROUP_ID,
    738                closedInTabGroup: true,
    739              }),
    740            ],
    741          },
    742        ],
    743      },
    744    ],
    745  });
    746 
    747  Assert.equal(
    748    SessionStore.getClosedTabCount(),
    749    4,
    750    "Sanity check number of closed tabs from closed windows"
    751  );
    752 
    753  let closeTabsPanel = await openRecentlyClosedTabsMenu();
    754 
    755  const topLevelClosedTabItems = closeTabsPanel
    756    .querySelector(".panel-subview-body")
    757    .querySelectorAll(":scope > toolbarbutton[targetURI]");
    758  Assert.equal(
    759    topLevelClosedTabItems.length,
    760    1,
    761    "We have the expected number of top-level closed tab items"
    762  );
    763 
    764  const tabGroupClosedTabItems = closeTabsPanel.querySelectorAll(
    765    `panelview#closed-tabs-tab-group-${GROUP_ID} toolbarbutton[targetURI]`
    766  );
    767  Assert.equal(
    768    tabGroupClosedTabItems.length,
    769    3,
    770    "We have the expected number of closed tab items within the tab group"
    771  );
    772 
    773  await hideHistoryPanel();
    774 
    775  await SessionStoreTestUtils.promiseBrowserState(ORIG_STATE);
    776 });
    777 
    778 add_task(async function testOpenTabFromClosedGroupInClosedWindow() {
    779  // Asserts fix for bug1944416
    780  info(
    781    "Open a tab from a closed tab group in a closed window as a standalone tab"
    782  );
    783  await Sanitizer.sanitize(["history"]);
    784  await resetClosedTabsAndWindows();
    785  const ORIG_STATE = SessionStore.getBrowserState();
    786 
    787  const closedTabUrl = "about:robots";
    788  const closedTabGroupUrls = ["about:logo", "https://example.com"];
    789  const closedTabGroupId = "1234567890-1";
    790 
    791  await SessionStoreTestUtils.promiseBrowserState({
    792    windows: [
    793      {
    794        tabs: [makeTabState("about:blank")],
    795        _closedTabs: [],
    796        closedGroups: [],
    797      },
    798    ],
    799    _closedWindows: [
    800      {
    801        tabs: [makeTabState("about:blank")],
    802        _closedTabs: [makeClosedTabState(closedTabUrl)],
    803        closedGroups: [
    804          {
    805            id: closedTabGroupId,
    806            color: "red",
    807            name: "tab-group",
    808            tabs: closedTabGroupUrls.map(url =>
    809              makeClosedTabState(url, {
    810                groupId: closedTabGroupId,
    811                closedInTabGroup: true,
    812              })
    813            ),
    814          },
    815        ],
    816      },
    817    ],
    818  });
    819 
    820  Assert.equal(
    821    SessionStore.getClosedTabCountFromClosedWindows(),
    822    closedTabGroupUrls.length + 1, // Add the lone ungrouped closed tab
    823    "Sanity check number of closed tabs from closed windows"
    824  );
    825 
    826  let closeTabsPanel = await openRecentlyClosedTabsMenu();
    827  const closedTabItems = closeTabsPanel.querySelectorAll(
    828    "toolbarbutton[targetURI]"
    829  );
    830 
    831  let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
    832  let closedObjectsChangePromise = TestUtils.topicObserved(
    833    "sessionstore-closed-objects-changed"
    834  );
    835  EventUtils.sendMouseEvent({ type: "click" }, closedTabItems[0], window);
    836  await newTabPromise;
    837  await closedObjectsChangePromise;
    838 
    839  Assert.equal(
    840    gBrowser.tabs.at(-1).linkedBrowser.currentURI.spec,
    841    closedTabUrl,
    842    "Ungrouped closed tab from closed window is opened correctly in the presence of closed tab groups"
    843  );
    844 
    845  closeTabsPanel = await openRecentlyClosedTabsMenu();
    846  const tabGroupClosedTabItems = closeTabsPanel.querySelectorAll(
    847    `panelview#closed-tabs-tab-group-${closedTabGroupId} toolbarbutton[targetURI]`
    848  );
    849 
    850  newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
    851  closedObjectsChangePromise = TestUtils.topicObserved(
    852    "sessionstore-closed-objects-changed"
    853  );
    854  EventUtils.sendMouseEvent(
    855    { type: "click" },
    856    tabGroupClosedTabItems[0],
    857    window
    858  );
    859  await newTabPromise;
    860  await closedObjectsChangePromise;
    861 
    862  Assert.equal(
    863    gBrowser.tabs.at(-1).linkedBrowser.currentURI.spec,
    864    closedTabGroupUrls[0],
    865    "Grouped closed tab from closed window is opened correctly"
    866  );
    867 
    868  await SessionStoreTestUtils.promiseBrowserState(ORIG_STATE);
    869 });
    870 
    871 add_task(async function testHistoryMenusWorkWithOldPreTabGroupsState() {
    872  info(
    873    "Ensure that a session file created before the release of tab groups does not prevent closed tabs in closed windows from opening"
    874  );
    875  // Fixes bug1947503
    876 
    877  // We need to make sure the history is cleared before starting the test
    878  await Sanitizer.sanitize(["history"]);
    879  await resetClosedTabsAndWindows();
    880  const ORIG_STATE = SessionStore.getBrowserState();
    881 
    882  const closedTabUrls = [
    883    "about:robots",
    884    "https://example.com/",
    885    "https://example.org/",
    886  ];
    887 
    888  await SessionStoreTestUtils.promiseBrowserState({
    889    windows: [
    890      {
    891        tabs: [makeTabState("about:mozilla")],
    892        _closedTabs: [],
    893        // No closedGroups element
    894      },
    895    ],
    896    _closedWindows: [
    897      {
    898        tabs: [makeTabState("about:mozilla")],
    899        _closedTabs: closedTabUrls.map(makeClosedTabState),
    900        // No closedGroups element
    901      },
    902    ],
    903  });
    904 
    905  is(gBrowser.visibleTabs.length, 1, "We start with one tab open");
    906  // Open the "Recently closed tabs" panel.
    907  let closeTabsPanel = await openRecentlyClosedTabsMenu();
    908 
    909  // Click the first toolbar button in the panel.
    910  let toolbarButton = closeTabsPanel.querySelector(
    911    ".panel-subview-body toolbarbutton"
    912  );
    913  let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
    914  EventUtils.sendMouseEvent({ type: "click" }, toolbarButton, window);
    915  let reopenedTab = await newTabPromise;
    916 
    917  is(gBrowser.tabs.length, 2, "Closed tab was restored");
    918 
    919  await SessionStoreTestUtils.closeTab(reopenedTab);
    920  await SessionStoreTestUtils.promiseBrowserState(ORIG_STATE);
    921 });