tor-browser

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

SessionStoreTestUtils.sys.mjs (6262B)


      1 const lazy = {};
      2 ChromeUtils.defineESModuleGetters(lazy, {
      3  BrowserTestUtils: "resource://testing-common/BrowserTestUtils.sys.mjs",
      4  SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
      5  TabStateFlusher: "resource:///modules/sessionstore/TabStateFlusher.sys.mjs",
      6  TestUtils: "resource://testing-common/TestUtils.sys.mjs",
      7 });
      8 
      9 export var SessionStoreTestUtils = {
     10  /**
     11   * Running this init allows helpers to access test scope helpers, like Assert
     12   * and SimpleTest.
     13   * Tests should call this init() before using the helpers which rely on properties assign here.
     14   *
     15   * @param {object} scope The global scope where tests are being run.
     16   * @param {DOmWindow} scope The global window object, for acessing gBrowser etc.
     17   */
     18  init(scope, windowGlobal) {
     19    if (!scope) {
     20      throw new Error(
     21        "Must initialize SessionStoreTestUtils with a test scope"
     22      );
     23    }
     24    if (!windowGlobal) {
     25      throw new Error("this.windowGlobal must be defined when we init");
     26    }
     27    this.info = scope.info;
     28    this.registerCleanupFunction = scope.registerCleanupFunction;
     29    this.windowGlobal = windowGlobal;
     30  },
     31 
     32  async closeTab(tab) {
     33    await lazy.TabStateFlusher.flush(tab.linkedBrowser);
     34    let sessionUpdatePromise =
     35      lazy.BrowserTestUtils.waitForSessionStoreUpdate(tab);
     36    lazy.BrowserTestUtils.removeTab(tab);
     37    await sessionUpdatePromise;
     38  },
     39 
     40  async openAndCloseTab(window, url) {
     41    let { updatePromise } = await lazy.BrowserTestUtils.withNewTab(
     42      { url, gBrowser: window.gBrowser },
     43      async browser => {
     44        return {
     45          updatePromise: lazy.BrowserTestUtils.waitForSessionStoreUpdate({
     46            linkedBrowser: browser,
     47          }),
     48        };
     49      }
     50    );
     51    await updatePromise;
     52    return lazy.TestUtils.topicObserved("sessionstore-closed-objects-changed");
     53  },
     54 
     55  // This assumes that tests will at least have some state/entries
     56  waitForBrowserState(aState, aSetStateCallback) {
     57    if (typeof aState == "string") {
     58      aState = JSON.parse(aState);
     59    }
     60    if (typeof aState != "object") {
     61      throw new TypeError(
     62        "Argument must be an object or a JSON representation of an object"
     63      );
     64    }
     65    if (!this.windowGlobal) {
     66      throw new Error(
     67        "no windowGlobal defined, please call init() first with the scope and window object"
     68      );
     69    }
     70    let windows = [this.windowGlobal];
     71    let tabsRestored = 0;
     72    let expectedTabsRestored = 0;
     73    let expectedWindows = aState.windows.length;
     74    let windowsOpen = 1;
     75    let listening = false;
     76    let windowObserving = false;
     77    let restoreHiddenTabs = Services.prefs.getBoolPref(
     78      "browser.sessionstore.restore_hidden_tabs"
     79    );
     80    // This should match the |restoreTabsLazily| value that
     81    // SessionStore.restoreWindow() uses.
     82    let restoreTabsLazily =
     83      Services.prefs.getBoolPref("browser.sessionstore.restore_on_demand") &&
     84      Services.prefs.getBoolPref("browser.sessionstore.restore_tabs_lazily");
     85 
     86    aState.windows.forEach(function (winState) {
     87      winState.tabs.forEach(function (tabState) {
     88        if (!restoreTabsLazily && (restoreHiddenTabs || !tabState.hidden)) {
     89          expectedTabsRestored++;
     90        }
     91      });
     92    });
     93 
     94    // If there are only hidden tabs and restoreHiddenTabs = false, we still
     95    // expect one of them to be restored because it gets shown automatically.
     96    // Otherwise if lazy tab restore there will only be one tab restored per window.
     97    if (!expectedTabsRestored) {
     98      expectedTabsRestored = 1;
     99    } else if (restoreTabsLazily) {
    100      expectedTabsRestored = aState.windows.length;
    101    }
    102 
    103    function onSSTabRestored() {
    104      if (++tabsRestored == expectedTabsRestored) {
    105        // Remove the event listener from each window
    106        windows.forEach(function (win) {
    107          win.gBrowser.tabContainer.removeEventListener(
    108            "SSTabRestored",
    109            onSSTabRestored,
    110            true
    111          );
    112        });
    113        listening = false;
    114        SessionStoreTestUtils.info("running " + aSetStateCallback.name);
    115        lazy.TestUtils.executeSoon(aSetStateCallback);
    116      }
    117    }
    118 
    119    // Used to add our listener to further windows so we can catch SSTabRestored
    120    // coming from them when creating a multi-window state.
    121    function windowObserver(aSubject, aTopic) {
    122      if (aTopic == "domwindowopened") {
    123        let newWindow = aSubject;
    124        newWindow.addEventListener(
    125          "load",
    126          function () {
    127            if (++windowsOpen == expectedWindows) {
    128              Services.ww.unregisterNotification(windowObserver);
    129              windowObserving = false;
    130            }
    131 
    132            // Track this window so we can remove the progress listener later
    133            windows.push(newWindow);
    134            // Add the progress listener
    135            newWindow.gBrowser.tabContainer.addEventListener(
    136              "SSTabRestored",
    137              onSSTabRestored,
    138              true
    139            );
    140          },
    141          { once: true }
    142        );
    143      }
    144    }
    145 
    146    // We only want to register the notification if we expect more than 1 window
    147    if (expectedWindows > 1) {
    148      this.registerCleanupFunction(function () {
    149        if (windowObserving) {
    150          Services.ww.unregisterNotification(windowObserver);
    151        }
    152      });
    153      windowObserving = true;
    154      Services.ww.registerNotification(windowObserver);
    155    }
    156 
    157    this.registerCleanupFunction(function () {
    158      if (listening) {
    159        windows.forEach(function (win) {
    160          win.gBrowser.tabContainer.removeEventListener(
    161            "SSTabRestored",
    162            onSSTabRestored,
    163            true
    164          );
    165        });
    166      }
    167    });
    168    // Add the event listener for this window as well.
    169    listening = true;
    170    this.windowGlobal.gBrowser.tabContainer.addEventListener(
    171      "SSTabRestored",
    172      onSSTabRestored,
    173      true
    174    );
    175 
    176    // Ensure setBrowserState() doesn't remove the initial tab.
    177    this.windowGlobal.gBrowser.selectedTab = this.windowGlobal.gBrowser.tabs[0];
    178 
    179    // Finally, call setBrowserState
    180    lazy.SessionStore.setBrowserState(JSON.stringify(aState));
    181  },
    182 
    183  promiseBrowserState(aState) {
    184    return new Promise(resolve => this.waitForBrowserState(aState, resolve));
    185  },
    186 };