tor-browser

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

browser_state_notifications.js (6886B)


      1 /* globals Components: true, Promise: true, gBrowser: true, Test: true,
      2           info: true, is: true, window: true, waitForExplicitFinish: true,
      3           finish: true, ok: true*/
      4 
      5 "use strict";
      6 
      7 const { addObserver, removeObserver } = Cc[
      8  "@mozilla.org/observer-service;1"
      9 ].getService(Ci.nsIObserverService);
     10 const { openWindow } = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService(
     11  Ci.nsIWindowWatcher
     12 );
     13 
     14 const Test = routine => () => {
     15  waitForExplicitFinish();
     16  routine().then(finish, error => {
     17    ok(false, error);
     18    finish();
     19  });
     20 };
     21 
     22 // Returns promise for the observer notification subject for
     23 // the given topic. If `receive("foo")` is called `n` times
     24 // nth promise is resolved on an `nth` "foo" notification.
     25 const receive = (topic, p, syncCallback) => {
     26  return new Promise((resolve, reject) => {
     27    const { queue } = receive;
     28    const timeout = () => {
     29      queue.splice(queue.indexOf(resolve) - 1, 2);
     30      reject(new Error("Timeout"));
     31    };
     32 
     33    const observer = {
     34      observe: subject => {
     35        // Browser loads bunch of other documents that we don't care
     36        // about so we let allow filtering notifications via `p` function.
     37        if (p && !p(subject)) {
     38          return;
     39        }
     40        // If observer is a first one with a given `topic`
     41        // in a queue resolve promise and take it off the queue
     42        // otherwise keep waiting.
     43        const index = queue.indexOf(topic);
     44        if (queue.indexOf(resolve) === index + 1) {
     45          removeObserver(observer, topic);
     46          clearTimeout(id, reject);
     47          queue.splice(index, 2);
     48          // Some tests need to be executed synchronously when the event is fired.
     49          if (syncCallback) {
     50            syncCallback(subject);
     51          }
     52          resolve(subject);
     53        }
     54      },
     55    };
     56    // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
     57    const id = setTimeout(timeout, 90000);
     58    addObserver(observer, topic, false);
     59    queue.push(topic, resolve);
     60  });
     61 };
     62 receive.queue = [];
     63 
     64 const openTab = uri =>
     65  (gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, uri));
     66 
     67 // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
     68 const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
     69 
     70 const isData = document => document.URL.startsWith("data:");
     71 
     72 const uri1 = "data:text/html;charset=utf-8,<h1>1</h1>";
     73 // For whatever reason going back on load event doesn't work so timeout it is :(
     74 const uri2 =
     75  "data:text/html;charset=utf-8,<h1>2</h1><script>setTimeout(SpecialPowers.wrap(window).back,100)</script>";
     76 const uri3 = "data:text/html;charset=utf-8,<h1>3</h1>";
     77 
     78 const uri4 = "chrome://browser/content/license.html";
     79 
     80 const test = Test(async function () {
     81  let documentInteractive = receive(
     82    "content-document-interactive",
     83    isData,
     84    d => {
     85      // This test is executed synchronously when the event is received.
     86      is(d.readyState, "interactive", "document is interactive");
     87      is(d.URL, uri1, "document.URL matches tab url");
     88    }
     89  );
     90  let documentLoaded = receive("content-document-loaded", isData);
     91  let pageShown = receive("content-page-shown", isData);
     92 
     93  info("open: uri#1");
     94  const tab1 = openTab(uri1);
     95  const browser1 = gBrowser.getBrowserForTab(tab1);
     96 
     97  let interactiveDocument1 = await documentInteractive;
     98 
     99  let loadedDocument1 = await documentLoaded;
    100  is(loadedDocument1.readyState, "complete", "document is loaded");
    101  is(interactiveDocument1, loadedDocument1, "interactive document is loaded");
    102 
    103  let shownPage = await pageShown;
    104  is(interactiveDocument1, shownPage, "loaded document is shown");
    105 
    106  // Wait until history entry is created before loading new uri.
    107  await receive("sessionstore-state-write-complete");
    108 
    109  info("load uri#2");
    110 
    111  documentInteractive = receive("content-document-interactive", isData, d => {
    112    // This test is executed synchronously when the event is received.
    113    is(d.readyState, "interactive", "document is interactive");
    114    is(d.URL, uri2, "document.URL matches URL loaded");
    115  });
    116  documentLoaded = receive("content-document-loaded", isData);
    117  pageShown = receive("content-page-shown", isData);
    118  let pageHidden = receive("content-page-hidden", isData);
    119 
    120  BrowserTestUtils.startLoadingURIString(browser1, uri2);
    121 
    122  let hiddenPage = await pageHidden;
    123  is(interactiveDocument1, hiddenPage, "loaded document is hidden");
    124 
    125  let interactiveDocument2 = await documentInteractive;
    126 
    127  let loadedDocument2 = await documentLoaded;
    128  is(loadedDocument2.readyState, "complete", "document is loaded");
    129  is(interactiveDocument2, loadedDocument2, "interactive document is loaded");
    130 
    131  shownPage = await pageShown;
    132  is(interactiveDocument2, shownPage, "loaded document is shown");
    133 
    134  info("go back to uri#1");
    135 
    136  documentInteractive = receive("content-document-interactive", isData, d => {
    137    // This test is executed synchronously when the event is received.
    138    is(d.readyState, "interactive", "document is interactive");
    139    is(d.URL, uri3, "document.URL matches URL loaded");
    140  });
    141  documentLoaded = receive("content-document-loaded", isData);
    142  pageShown = receive("content-page-shown", isData);
    143  pageHidden = receive("content-page-hidden", isData);
    144 
    145  hiddenPage = await pageHidden;
    146  is(interactiveDocument2, hiddenPage, "new document is hidden");
    147 
    148  shownPage = await pageShown;
    149  is(interactiveDocument1, shownPage, "previous document is shown");
    150 
    151  info("load uri#3");
    152 
    153  BrowserTestUtils.startLoadingURIString(browser1, uri3);
    154 
    155  pageShown = receive("content-page-shown", isData);
    156 
    157  let interactiveDocument3 = await documentInteractive;
    158 
    159  let loadedDocument3 = await documentLoaded;
    160  is(loadedDocument3.readyState, "complete", "document is loaded");
    161  is(interactiveDocument3, loadedDocument3, "interactive document is loaded");
    162 
    163  shownPage = await pageShown;
    164  is(interactiveDocument3, shownPage, "previous document is shown");
    165 
    166  gBrowser.removeTab(tab1);
    167 
    168  info("load chrome uri");
    169 
    170  const tab2 = openTab(uri4);
    171  documentInteractive = receive("chrome-document-interactive", null, d => {
    172    // This test is executed synchronously when the event is received.
    173    is(d.readyState, "interactive", "document is interactive");
    174    is(d.URL, uri4, "document.URL matches URL loaded");
    175  });
    176  documentLoaded = receive("chrome-document-loaded");
    177  pageShown = receive("chrome-page-shown");
    178 
    179  const interactiveDocument4 = await documentInteractive;
    180 
    181  let loadedDocument4 = await documentLoaded;
    182  is(loadedDocument4.readyState, "complete", "document is loaded");
    183  is(interactiveDocument4, loadedDocument4, "interactive document is loaded");
    184 
    185  shownPage = await pageShown;
    186  is(interactiveDocument4, shownPage, "loaded chrome document is shown");
    187 
    188  pageHidden = receive("chrome-page-hidden");
    189  gBrowser.removeTab(tab2);
    190 
    191  hiddenPage = await pageHidden;
    192  is(interactiveDocument4, hiddenPage, "chrome document hidden");
    193 });