tor-browser

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

head.js (8847B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const TEST_QUOTA_USAGE_HOST = "example.com";
      7 const TEST_QUOTA_USAGE_ORIGIN = "https://" + TEST_QUOTA_USAGE_HOST;
      8 const TEST_QUOTA_USAGE_URL =
      9  getRootDirectory(gTestPath).replace(
     10    "chrome://mochitests/content",
     11    TEST_QUOTA_USAGE_ORIGIN
     12  ) + "/site_data_test.html";
     13 const TEST_OFFLINE_HOST = "example.org";
     14 const TEST_OFFLINE_ORIGIN = "https://" + TEST_OFFLINE_HOST;
     15 const TEST_OFFLINE_URL =
     16  getRootDirectory(gTestPath).replace(
     17    "chrome://mochitests/content",
     18    TEST_OFFLINE_ORIGIN
     19  ) + "/offline/offline.html";
     20 const TEST_SERVICE_WORKER_URL =
     21  getRootDirectory(gTestPath).replace(
     22    "chrome://mochitests/content",
     23    TEST_OFFLINE_ORIGIN
     24  ) + "/service_worker_test.html";
     25 
     26 const REMOVE_DIALOG_URL =
     27  "chrome://browser/content/preferences/dialogs/siteDataRemoveSelected.xhtml";
     28 
     29 ChromeUtils.defineESModuleGetters(this, {
     30  SiteDataTestUtils: "resource://testing-common/SiteDataTestUtils.sys.mjs",
     31 });
     32 
     33 XPCOMUtils.defineLazyServiceGetter(
     34  this,
     35  "serviceWorkerManager",
     36  "@mozilla.org/serviceworkers/manager;1",
     37  Ci.nsIServiceWorkerManager
     38 );
     39 
     40 function promiseSiteDataManagerSitesUpdated() {
     41  return TestUtils.topicObserved("sitedatamanager:sites-updated", () => true);
     42 }
     43 
     44 function is_element_visible(aElement, aMsg) {
     45  isnot(aElement, null, "Element should not be null, when checking visibility");
     46  ok(!BrowserTestUtils.isHidden(aElement), aMsg);
     47 }
     48 
     49 function is_element_hidden(aElement, aMsg) {
     50  isnot(aElement, null, "Element should not be null, when checking visibility");
     51  ok(BrowserTestUtils.isHidden(aElement), aMsg);
     52 }
     53 
     54 function promiseLoadSubDialog(aURL) {
     55  return new Promise(resolve => {
     56    content.gSubDialog._dialogStack.addEventListener(
     57      "dialogopen",
     58      function dialogopen(aEvent) {
     59        if (
     60          aEvent.detail.dialog._frame.contentWindow.location == "about:blank"
     61        ) {
     62          return;
     63        }
     64        content.gSubDialog._dialogStack.removeEventListener(
     65          "dialogopen",
     66          dialogopen
     67        );
     68 
     69        is(
     70          aEvent.detail.dialog._frame.contentWindow.location.toString(),
     71          aURL,
     72          "Check the proper URL is loaded"
     73        );
     74 
     75        // Check visibility
     76        is_element_visible(aEvent.detail.dialog._overlay, "Overlay is visible");
     77 
     78        // Check that stylesheets were injected
     79        let expectedStyleSheetURLs =
     80          aEvent.detail.dialog._injectedStyleSheets.slice(0);
     81        for (let styleSheet of aEvent.detail.dialog._frame.contentDocument
     82          .styleSheets) {
     83          let i = expectedStyleSheetURLs.indexOf(styleSheet.href);
     84          if (i >= 0) {
     85            info("found " + styleSheet.href);
     86            expectedStyleSheetURLs.splice(i, 1);
     87          }
     88        }
     89        is(
     90          expectedStyleSheetURLs.length,
     91          0,
     92          "All expectedStyleSheetURLs should have been found"
     93        );
     94 
     95        // Wait for the next event tick to make sure the remaining part of the
     96        // testcase runs after the dialog gets ready for input.
     97        executeSoon(() => resolve(aEvent.detail.dialog._frame.contentWindow));
     98      }
     99    );
    100  });
    101 }
    102 
    103 function openPreferencesViaOpenPreferencesAPI(aPane, aOptions) {
    104  return new Promise(resolve => {
    105    let finalPrefPaneLoaded = TestUtils.topicObserved(
    106      "sync-pane-loaded",
    107      () => true
    108    );
    109    gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:blank");
    110    openPreferences(aPane);
    111    let newTabBrowser = gBrowser.selectedBrowser;
    112 
    113    newTabBrowser.addEventListener(
    114      "Initialized",
    115      function () {
    116        newTabBrowser.contentWindow.addEventListener(
    117          "load",
    118          async function () {
    119            let win = gBrowser.contentWindow;
    120            let selectedPane = win.history.state;
    121            await finalPrefPaneLoaded;
    122            if (!aOptions || !aOptions.leaveOpen) {
    123              gBrowser.removeCurrentTab();
    124            }
    125            resolve({ selectedPane });
    126          },
    127          { once: true }
    128        );
    129      },
    130      { capture: true, once: true }
    131    );
    132  });
    133 }
    134 
    135 async function openSiteDataSettingsDialog() {
    136  let doc = gBrowser.selectedBrowser.contentDocument;
    137  let settingsBtn = doc.getElementById("siteDataSettings");
    138  let dialogOverlay = content.gSubDialog._preloadDialog._overlay;
    139  let dialogLoadPromise = promiseLoadSubDialog(
    140    "chrome://browser/content/preferences/dialogs/siteDataSettings.xhtml"
    141  );
    142  let dialogInitPromise = TestUtils.topicObserved(
    143    "sitedata-settings-init",
    144    () => true
    145  );
    146  let fullyLoadPromise = Promise.all([
    147    dialogLoadPromise,
    148    dialogInitPromise,
    149  ]).then(() => {
    150    is_element_visible(dialogOverlay, "The Settings dialog should be visible");
    151  });
    152  // Wait for the dialog button to be enabled. It is disabled while
    153  // SiteDataManager updates the site list and usage.
    154  await BrowserTestUtils.waitForMutationCondition(
    155    settingsBtn,
    156    {
    157      attributeFilter: ["disabled"],
    158    },
    159    () => {
    160      return !settingsBtn.disabled;
    161    }
    162  );
    163  settingsBtn.click();
    164  await fullyLoadPromise;
    165 }
    166 
    167 function promiseSettingsDialogClose() {
    168  return new Promise(resolve => {
    169    let win = gBrowser.selectedBrowser.contentWindow;
    170    let dialogOverlay = win.gSubDialog._topDialog._overlay;
    171    let dialogWin = win.gSubDialog._topDialog._frame.contentWindow;
    172    dialogWin.addEventListener(
    173      "unload",
    174      function unload() {
    175        if (
    176          dialogWin.document.documentURI ===
    177          "chrome://browser/content/preferences/dialogs/siteDataSettings.xhtml"
    178        ) {
    179          is_element_hidden(
    180            dialogOverlay,
    181            "The Settings dialog should be hidden"
    182          );
    183          resolve();
    184        }
    185      },
    186      { once: true }
    187    );
    188  });
    189 }
    190 
    191 function assertSitesListed(doc, hosts) {
    192  let frameDoc = content.gSubDialog._topDialog._frame.contentDocument;
    193  let removeAllBtn = frameDoc.getElementById("removeAll");
    194  let sitesList = frameDoc.getElementById("sitesList");
    195  let totalSitesNumber = sitesList.getElementsByTagName("richlistitem").length;
    196  is(totalSitesNumber, hosts.length, "Should list the right sites number");
    197  hosts.forEach(host => {
    198    let site = sitesList.querySelector(`richlistitem[host="${host}"]`);
    199    ok(site, `Should list the site of ${host}`);
    200  });
    201  is(removeAllBtn.disabled, false, "Should enable the removeAllBtn button");
    202 }
    203 
    204 // Counter used by addTestData to generate unique cookie names across function
    205 // calls.
    206 let cookieID = 0;
    207 
    208 async function addTestData(data) {
    209  let hosts = new Set();
    210 
    211  for (let site of data) {
    212    is(
    213      typeof site.origin,
    214      "string",
    215      "Passed an origin string into addTestData."
    216    );
    217    if (site.persisted) {
    218      await SiteDataTestUtils.persist(site.origin);
    219    }
    220 
    221    if (site.usage) {
    222      await SiteDataTestUtils.addToIndexedDB(site.origin, site.usage);
    223    }
    224 
    225    for (let i = 0; i < (site.cookies || 0); i++) {
    226      SiteDataTestUtils.addToCookies({
    227        origin: site.origin,
    228        name: `cookie${cookieID++}`,
    229      });
    230    }
    231 
    232    let principal =
    233      Services.scriptSecurityManager.createContentPrincipalFromOrigin(
    234        site.origin
    235      );
    236 
    237    hosts.add(principal.baseDomain || principal.host);
    238  }
    239 
    240  return Array.from(hosts);
    241 }
    242 
    243 function promiseCookiesCleared() {
    244  return TestUtils.topicObserved("cookie-changed", subj => {
    245    return (
    246      subj.QueryInterface(Ci.nsICookieNotification).action ==
    247      Ci.nsICookieNotification.ALL_COOKIES_CLEARED
    248    );
    249  });
    250 }
    251 
    252 async function loadServiceWorkerTestPage(url) {
    253  let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
    254  await TestUtils.waitForCondition(() => {
    255    return SpecialPowers.spawn(
    256      tab.linkedBrowser,
    257      [],
    258      () =>
    259        content.document.body.getAttribute(
    260          "data-test-service-worker-registered"
    261        ) === "true"
    262    );
    263  }, `Fail to load service worker test ${url}`);
    264  BrowserTestUtils.removeTab(tab);
    265 }
    266 
    267 function promiseServiceWorkersCleared() {
    268  return TestUtils.waitForCondition(() => {
    269    let serviceWorkers = serviceWorkerManager.getAllRegistrations();
    270    if (!serviceWorkers.length) {
    271      ok(true, "Cleared all service workers");
    272      return true;
    273    }
    274    return false;
    275  }, "Should clear all service workers");
    276 }
    277 
    278 function promiseServiceWorkerRegisteredFor(url) {
    279  return TestUtils.waitForCondition(() => {
    280    try {
    281      let principal =
    282        Services.scriptSecurityManager.createContentPrincipalFromOrigin(url);
    283      let sw = serviceWorkerManager.getRegistrationByPrincipal(
    284        principal,
    285        principal.spec
    286      );
    287      if (sw) {
    288        ok(true, `Found the service worker registered for ${url}`);
    289        return true;
    290      }
    291    } catch (e) {}
    292    return false;
    293  }, `Should register service worker for ${url}`);
    294 }