tor-browser

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

browser_closed_tabs_closed_windows.js (10285B)


      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 const { TelemetryTestUtils } = ChromeUtils.importESModule(
      5  "resource://testing-common/TelemetryTestUtils.sys.mjs"
      6 );
      7 const TEST_URLS = [
      8  "http://mochi.test:8888/browser/",
      9  "https://www.example.com/",
     10  "https://example.net/",
     11  "https://example.org/",
     12  "about:logo",
     13  "about:robots",
     14 ];
     15 const TOPIC_CLOSED_OBJECTS_CHANGED = "sessionstore-closed-objects-changed";
     16 var preparedClosedIds;
     17 
     18 add_setup(async function testSetup() {
     19  registerCleanupFunction(async () => {
     20    await promiseAllButPrimaryWindowClosed();
     21    Services.obs.notifyObservers(null, "browser:purge-session-history");
     22  });
     23  preparedClosedIds = await prepareClosedData();
     24  SimpleTest.promiseFocus(window);
     25 });
     26 
     27 async function prepareClosedData() {
     28  // prepare some closed state
     29  let closedIds = {};
     30  await openAndCloseTab(window, TEST_URLS[0]);
     31  closedIds.tab0 = SessionStore.getClosedTabDataForWindow(window)[0].closedId;
     32 
     33  const testWindow1 = await BrowserTestUtils.openNewBrowserWindow();
     34  // open a non-transitory, worth-keeping tab to ensure window data is saved on close
     35  await BrowserTestUtils.openNewForegroundTab(
     36    testWindow1.gBrowser,
     37    "about:mozilla"
     38  );
     39  await openAndCloseTab(testWindow1, TEST_URLS[1]);
     40  closedIds.tab1 =
     41    SessionStore.getClosedTabDataForWindow(testWindow1)[0].closedId;
     42 
     43  const testWindow2 = await BrowserTestUtils.openNewBrowserWindow();
     44  // open a non-transitory, worth-keeping tab to ensure window data is saved on close
     45  await BrowserTestUtils.openNewForegroundTab(
     46    testWindow2.gBrowser,
     47    "about:mozilla"
     48  );
     49  await openAndCloseTab(testWindow2, TEST_URLS[2]);
     50  closedIds.tab2 =
     51    SessionStore.getClosedTabDataForWindow(testWindow2)[0].closedId;
     52  await openAndCloseTab(testWindow2, TEST_URLS[3]);
     53  closedIds.tab3 =
     54    SessionStore.getClosedTabDataForWindow(testWindow2)[0].closedId;
     55 
     56  const testWindow3 = await BrowserTestUtils.openNewBrowserWindow();
     57  // open a non-transitory, worth-keeping tab to ensure window data is saved on close
     58  await BrowserTestUtils.openNewForegroundTab(
     59    testWindow3.gBrowser,
     60    "about:mozilla"
     61  );
     62  await openAndCloseTab(testWindow3, TEST_URLS[4]);
     63  closedIds.tab4 =
     64    SessionStore.getClosedTabDataForWindow(testWindow3)[0].closedId;
     65 
     66  // open a private window
     67  const privateWin = await BrowserTestUtils.openNewBrowserWindow({
     68    private: true,
     69  });
     70  // open a non-transitory, worth-keeping tab to ensure window data is saved on close
     71  await BrowserTestUtils.openNewForegroundTab(
     72    privateWin.gBrowser,
     73    "about:mozilla"
     74  );
     75  await openAndCloseTab(privateWin, TEST_URLS[5]);
     76  closedIds.tab5 =
     77    SessionStore.getClosedTabDataForWindow(privateWin)[0].closedId;
     78 
     79  const testWindow6 = await BrowserTestUtils.openNewBrowserWindow();
     80 
     81  const testWindow7 = await BrowserTestUtils.openNewBrowserWindow();
     82  await openAndCloseTab(testWindow7, TEST_URLS[4]);
     83 
     84  await BrowserTestUtils.closeWindow(testWindow1);
     85  closedIds.testWindow1 = SessionStore.getClosedWindowData()[0].closedId;
     86  await BrowserTestUtils.closeWindow(testWindow2);
     87 
     88  closedIds.testWindow2 = SessionStore.getClosedWindowData()[0].closedId;
     89  await BrowserTestUtils.closeWindow(testWindow3);
     90 
     91  closedIds.testWindow3 = SessionStore.getClosedWindowData()[0].closedId;
     92  await BrowserTestUtils.closeWindow(privateWin);
     93  Assert.greater(
     94    closedIds.testWindow2,
     95    closedIds.testWindow1,
     96    "We got the closedIds in the expected order"
     97  );
     98 
     99  await BrowserTestUtils.closeWindow(testWindow6);
    100  await BrowserTestUtils.closeWindow(testWindow7);
    101  return closedIds;
    102 }
    103 
    104 // The tasks need to be run sequentially. They are broken up so the different functions
    105 // under test and any stack traces are easier to find
    106 
    107 add_task(async function get_closed_tabs_from_closed_windows() {
    108  Assert.equal(
    109    SessionStore.getClosedTabCount({ closedTabsFromClosedWindows: false }),
    110    1,
    111    "Expected closed tab count (in currently-open windows only)"
    112  );
    113  Assert.equal(
    114    SessionStore.getClosedTabCount(),
    115    5,
    116    "Expected closed tab count (in currently-open and closed windows)"
    117  );
    118  // We dont keep the closed tab from the private window
    119  Assert.equal(
    120    SessionStore.getClosedTabCountFromClosedWindows(),
    121    4,
    122    "Expected closed tab count (from closed windows)"
    123  );
    124 
    125  // Closed tabs from closed windows aren't included in the list from getClosedTabData()
    126  Assert.deepEqual(
    127    SessionStore.getClosedTabData().map(td => td.state.entries[0].url),
    128    ["http://mochi.test:8888/browser/"],
    129    "Matched closed tab data from currently open windows"
    130  );
    131 
    132  // Closed tabs from open windows or closed private windows aren't included in the list
    133  // from getClosedTabDataFromClosedWindows()
    134  Assert.deepEqual(
    135    SessionStore.getClosedTabDataFromClosedWindows().map(
    136      td => td.state.entries[0].url
    137    ),
    138    [
    139      "about:logo",
    140      "https://example.org/",
    141      "https://example.net/",
    142      "https://www.example.com/",
    143    ],
    144    "Matched closed tab data from currently closed windows"
    145  );
    146 });
    147 
    148 add_task(async function forget_closed_tabs_from_closed_windows() {
    149  // forget the most recent tab we closed in testWindow1
    150  let closedObjectsChanged = TestUtils.topicObserved(
    151    TOPIC_CLOSED_OBJECTS_CHANGED
    152  );
    153  info(
    154    "Calling forgetClosedTab with window sourceClosedId: " +
    155      preparedClosedIds.testWindow1
    156  );
    157  SessionStore.forgetClosedTab(
    158    { sourceClosedId: preparedClosedIds.testWindow1 },
    159    0
    160  );
    161  await closedObjectsChanged;
    162  Assert.deepEqual(
    163    SessionStore.getClosedTabDataFromClosedWindows().map(
    164      td => td.state.entries[0].url
    165    ),
    166    [
    167      "about:logo",
    168      "https://example.org/",
    169      "https://example.net/",
    170      // "https://www.example.com/" from testWindow1 was forgotten and should be removed
    171    ],
    172    "Closed tab forgotten"
    173  );
    174 
    175  // forget a closed window that had closed tabs
    176  let closedTabCount = SessionStore.getClosedTabCountFromClosedWindows();
    177  closedObjectsChanged = TestUtils.topicObserved(TOPIC_CLOSED_OBJECTS_CHANGED);
    178  SessionStore.forgetClosedWindowById(preparedClosedIds.testWindow3);
    179  await closedObjectsChanged;
    180  Assert.equal(
    181    SessionStore.getClosedTabCountFromClosedWindows(),
    182    closedTabCount - 1,
    183    "The closed tab is gone when we forget the closed window it was in"
    184  );
    185 });
    186 
    187 add_task(async function expected_exceptions_closed_tabs_from_closed_windows() {
    188  // testWindow3 was forgotten, attempting to undoClose its tabs should throw
    189  Assert.throws(
    190    () =>
    191      SessionStore.undoClosedTabFromClosedWindow(
    192        { sourceClosedId: preparedClosedIds.testWindow3 },
    193        preparedClosedIds.tab4
    194      ),
    195    /NS_ERROR_ILLEGAL_VALUE/,
    196    "Invalid window or source for undoClosedTabFromClosedWindow throws"
    197  );
    198  // tab1 was forgotten, attempting to undoClose it should throw
    199  Assert.throws(
    200    () =>
    201      SessionStore.undoClosedTabFromClosedWindow(
    202        { sourceClosedId: preparedClosedIds.testWindow1 },
    203        preparedClosedIds.tab1
    204      ),
    205    /NS_ERROR_ILLEGAL_VALUE/,
    206    "Invalid tab closedId for undoClosedTabFromClosedWindow throws"
    207  );
    208 
    209  // testWindow3 was forgotten, attempting to forget its tabs should throw
    210  Assert.throws(
    211    () =>
    212      SessionStore.forgetClosedTab(
    213        { sourceClosedId: preparedClosedIds.testWindow3 },
    214        preparedClosedIds.tab4
    215      ),
    216    /NS_ERROR_ILLEGAL_VALUE/,
    217    "Invalid window or source for forgetClosedTab throws"
    218  );
    219 
    220  // tab1 was forgotten, attempting to forget it again should throw
    221  Assert.throws(
    222    () =>
    223      SessionStore.undoClosedTabFromClosedWindow(
    224        { sourceClosedId: preparedClosedIds.testWindow3 },
    225        preparedClosedIds.tab4
    226      ),
    227    /NS_ERROR_ILLEGAL_VALUE/,
    228    "Invalid window for undoClosedTabFromClosedWindow throws"
    229  );
    230 });
    231 
    232 add_task(async function undo_closed_tabs_from_closed_windows() {
    233  const openTabsCount = gBrowser.tabs.length;
    234 
    235  // undo most recently closed tab from a closed window using a window closedId
    236  let closedObjectsChanged = TestUtils.topicObserved(
    237    TOPIC_CLOSED_OBJECTS_CHANGED
    238  );
    239  let restoredTab1 = SessionStore.undoCloseTab(
    240    { sourceClosedId: preparedClosedIds.testWindow2 },
    241    0,
    242    window
    243  );
    244  await BrowserTestUtils.waitForEvent(
    245    window.gBrowser.tabContainer,
    246    "SSTabRestored"
    247  );
    248  await closedObjectsChanged;
    249  Assert.equal(
    250    window.gBrowser.tabs.length,
    251    openTabsCount + 1,
    252    "The closed tab was restored"
    253  );
    254  Assert.equal(
    255    restoredTab1.linkedBrowser.currentURI.spec,
    256    "https://example.org/",
    257    "The re-opened tab had the expected URL"
    258  );
    259  Assert.deepEqual(
    260    SessionStore.getClosedTabDataFromClosedWindows().map(
    261      td => td.state.entries[0].url
    262    ),
    263    [
    264      "https://example.net/",
    265      // "https://example.org/" from testWindow2 got reopened and should be removed
    266    ],
    267    "Re-opened tabs not listed in closed tabs"
    268  );
    269 
    270  // use undoClosedTabFromClosedWindows to reference the closed tab by closedId
    271  closedObjectsChanged = TestUtils.topicObserved(TOPIC_CLOSED_OBJECTS_CHANGED);
    272  let restoredTab2 = SessionStore.undoClosedTabFromClosedWindow(
    273    { sourceClosedId: preparedClosedIds.testWindow2 },
    274    preparedClosedIds.tab2,
    275    window
    276  );
    277  await BrowserTestUtils.waitForEvent(
    278    window.gBrowser.tabContainer,
    279    "SSTabRestored"
    280  );
    281  await closedObjectsChanged;
    282  Assert.equal(
    283    window.gBrowser.tabs.length,
    284    openTabsCount + 2,
    285    "The closed tab was restored"
    286  );
    287  Assert.equal(
    288    restoredTab2.linkedBrowser.currentURI.spec,
    289    "https://example.net/",
    290    "The re-opened tab had the expected URL"
    291  );
    292 
    293  Assert.deepEqual(
    294    SessionStore.getClosedTabDataFromClosedWindows().map(
    295      td => td.state.entries[0].url
    296    ),
    297    [
    298      // "https://example.org/" from testWindow2 got reopened and should be removed
    299    ],
    300    "Re-opened tabs not listed in closed tabs"
    301  );
    302 
    303  // clean up the re-opened tabs
    304  for (let tab of [restoredTab1, restoredTab2]) {
    305    await TabStateFlusher.flush(tab.linkedBrowser);
    306    let sessionUpdatePromise = BrowserTestUtils.waitForSessionStoreUpdate(tab);
    307    BrowserTestUtils.removeTab(tab);
    308    await sessionUpdatePromise;
    309  }
    310 });