tor-browser

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

head.js (6287B)


      1 async function newFocusedWindow(trigger, isInitialBlank = false) {
      2  let winPromise = BrowserTestUtils.domWindowOpenedAndLoaded();
      3  let delayedStartupPromise = BrowserTestUtils.waitForNewWindow();
      4 
      5  await trigger();
      6 
      7  let win = await winPromise;
      8  // New windows get focused after the first paint, see bug 1262946,
      9  // but this is racy for the initial about:blank
     10  if (!isInitialBlank) {
     11    await BrowserTestUtils.waitForContentEvent(
     12      win.gBrowser.selectedBrowser,
     13      "MozAfterPaint"
     14    );
     15  } else {
     16    await new Promise(res =>
     17      win.requestAnimationFrame(() => win.requestAnimationFrame(res))
     18    );
     19  }
     20  await delayedStartupPromise;
     21  return win;
     22 }
     23 
     24 const JS_CACHE_BASE_URL = "http://mochi.test:8888/browser/dom/base/test/";
     25 
     26 function ev(event, file, hasElement = !!file) {
     27  return {
     28    event,
     29    url: file ? JS_CACHE_BASE_URL + file : undefined,
     30    hasElement,
     31  };
     32 }
     33 
     34 function unordered(list) {
     35  return {
     36    unordered: list,
     37  };
     38 }
     39 
     40 function optional_ev(...args) {
     41  const event = ev(...args);
     42  event.optional = true;
     43  return event;
     44 }
     45 
     46 async function jsCacheContentTask(test, item) {
     47  const defaultSkippedEvents = test.skippedEvents ?? [
     48    // The compilation is not target of this test.
     49    "compile:main thread",
     50    // This is triggered by 'invalidateMemory' below, but we don't have to
     51    // track it.
     52    "memorycache:invalidate",
     53    // The disk cache handling for the in-memory cache can happen multiple
     54    // times depending on the scheduling and speed
     55    // (e.g. debug vs opt, verify mode).
     56    "diskcache:noschedule",
     57  ];
     58  const nonSkippedEvents = test.nonSkippedEvents ?? [];
     59  const skippedEvents = defaultSkippedEvents.filter(
     60    ev => !nonSkippedEvents.includes(ev)
     61  );
     62 
     63  function match(param, event) {
     64    if (event.event !== param.event) {
     65      return false;
     66    }
     67 
     68    if (param.url && event.url !== param.url) {
     69      return false;
     70    }
     71 
     72    if (event.hasElement) {
     73      if (param.id !== "watchme") {
     74        return false;
     75      }
     76    } else {
     77      if (param.id) {
     78        return false;
     79      }
     80    }
     81 
     82    return true;
     83  }
     84 
     85  function consumeIfMatched(param, events) {
     86    while ("optional" in events[0]) {
     87      if (match(param, events[0])) {
     88        events.shift();
     89        return true;
     90      }
     91      dump("@@@ Skip optional event: " + events[0].event + "\n");
     92      events.shift();
     93    }
     94 
     95    if ("unordered" in events[0]) {
     96      const unordered = events[0].unordered;
     97      for (let i = 0; i < unordered.length; i++) {
     98        if (match(param, unordered[i])) {
     99          unordered.splice(i, 1);
    100          if (!unordered.length) {
    101            events.shift();
    102          }
    103          return true;
    104        }
    105      }
    106 
    107      return false;
    108    }
    109 
    110    if (match(param, events[0])) {
    111      events.shift();
    112      return true;
    113    }
    114 
    115    return false;
    116  }
    117 
    118  let result = true;
    119 
    120  const { promise, resolve, reject } = Promise.withResolvers();
    121  const observer = function (subject, topic, data) {
    122    const param = {};
    123    for (const line of data.split("\n")) {
    124      const m = line.match(/^([^:]+):(.*)/);
    125      param[m[1]] = m[2];
    126    }
    127 
    128    if (consumeIfMatched(param, item.events)) {
    129      dump("@@@ Got expected event: " + data + "\n");
    130      if (item.events.length === 0) {
    131        resolve();
    132      }
    133    } else if (skippedEvents.includes(param.event)) {
    134      dump("@@@ Ignoring: " + data + "\n");
    135    } else {
    136      dump("@@@ Got unexpected event: " + data + "\n");
    137      dump("@@@ Expected: " + JSON.stringify(item.events[0]) + "\n");
    138      result = false;
    139    }
    140  };
    141  Services.obs.addObserver(observer, "ScriptLoaderTest");
    142 
    143  const script = content.document.createElement("script");
    144  script.id = "watchme";
    145  if (test.module || item.module) {
    146    script.type = "module";
    147  }
    148  if (item.sri) {
    149    script.integrity = item.sri;
    150  }
    151  script.src = item.file;
    152  content.document.body.appendChild(script);
    153 
    154  await promise;
    155 
    156  Services.obs.removeObserver(observer, "ScriptLoaderTest");
    157 
    158  return result;
    159 }
    160 
    161 async function runJSCacheTests(tests) {
    162  await BrowserTestUtils.withNewTab(
    163    JS_CACHE_BASE_URL + "empty.html",
    164    async browser => {
    165      const tab = gBrowser.getTabForBrowser(browser);
    166 
    167      for (const test of tests) {
    168        ChromeUtils.clearResourceCache();
    169        Services.cache2.clear();
    170 
    171        if (test.useServiceWorker) {
    172          await SpecialPowers.spawn(browser, [], async () => {
    173            const registration = await content.navigator.serviceWorker.register(
    174              "file_js_cache_sw.js",
    175              { scope: "./" }
    176            );
    177 
    178            const sw = registration.installing || registration.active;
    179 
    180            await new Promise(resolve => {
    181              function onStateChange() {
    182                if (sw.state === "activated") {
    183                  sw.removeEventListener("statechange", onStateChange);
    184                  resolve();
    185                }
    186              }
    187              sw.addEventListener("statechange", onStateChange);
    188              onStateChange();
    189            });
    190          });
    191        }
    192 
    193        for (let i = 0; i < test.items.length; i++) {
    194          const item = test.items[i];
    195          info(`start: ${test.title} (item ${i})`);
    196 
    197          if (!test.skipReload) {
    198            // Make sure the test starts in clean document.
    199            await BrowserTestUtils.reloadTab(tab);
    200          }
    201 
    202          if (item.clearMemory) {
    203            info("clear memory cache");
    204            ChromeUtils.clearResourceCache();
    205          }
    206          if (item.invalidateMemory) {
    207            info("invalidate memory cache");
    208            ChromeUtils.invalidateResourceCache();
    209          }
    210          if (item.clearDisk) {
    211            info("clear disk cache");
    212            Services.cache2.clear();
    213          }
    214          const result = await SpecialPowers.spawn(
    215            browser,
    216            [test, item],
    217            jsCacheContentTask
    218          );
    219          ok(result, "Received expected events");
    220        }
    221 
    222        if (test.useServiceWorker) {
    223          await SpecialPowers.spawn(browser, [], async () => {
    224            const registration =
    225              await content.navigator.serviceWorker.getRegistration();
    226            registration.unregister();
    227          });
    228        }
    229 
    230        ok(true, "end: " + test.title);
    231      }
    232    }
    233  );
    234 
    235  ok(true, "Finished all tests");
    236 }