tor-browser

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

browser_onbeforeunload_navigation.js (4630B)


      1 "use strict";
      2 
      3 const TEST_PAGE =
      4  "http://mochi.test:8888/browser/docshell/test/browser/file_bug1046022.html";
      5 const TARGETED_PAGE =
      6  "data:text/html," +
      7  encodeURIComponent("<body>Shouldn't be seeing this</body>");
      8 
      9 const { PromptTestUtils } = ChromeUtils.importESModule(
     10  "resource://testing-common/PromptTestUtils.sys.mjs"
     11 );
     12 
     13 var loadStarted = false;
     14 var tabStateListener = {
     15  resolveLoad: null,
     16  expectLoad: null,
     17 
     18  onStateChange(webprogress, request, flags) {
     19    const WPL = Ci.nsIWebProgressListener;
     20    if (flags & WPL.STATE_IS_WINDOW) {
     21      if (flags & WPL.STATE_START) {
     22        loadStarted = true;
     23      } else if (flags & WPL.STATE_STOP) {
     24        let url = request.QueryInterface(Ci.nsIChannel).URI.spec;
     25        is(url, this.expectLoad, "Should only see expected document loads");
     26        if (url == this.expectLoad) {
     27          this.resolveLoad();
     28        }
     29      }
     30    }
     31  },
     32  QueryInterface: ChromeUtils.generateQI([
     33    "nsIWebProgressListener",
     34    "nsISupportsWeakReference",
     35  ]),
     36 };
     37 
     38 function promiseLoaded(url, callback) {
     39  if (tabStateListener.expectLoad) {
     40    throw new Error("Can't wait for multiple loads at once");
     41  }
     42  tabStateListener.expectLoad = url;
     43  return new Promise(resolve => {
     44    tabStateListener.resolveLoad = resolve;
     45    if (callback) {
     46      callback();
     47    }
     48  }).then(() => {
     49    tabStateListener.expectLoad = null;
     50    tabStateListener.resolveLoad = null;
     51  });
     52 }
     53 
     54 function promiseStayOnPagePrompt(browser, acceptNavigation) {
     55  return PromptTestUtils.handleNextPrompt(
     56    browser,
     57    { modalType: Services.prompt.MODAL_TYPE_CONTENT, promptType: "confirmEx" },
     58    { buttonNumClick: acceptNavigation ? 0 : 1 }
     59  );
     60 }
     61 
     62 add_task(async function test() {
     63  await SpecialPowers.pushPrefEnv({
     64    set: [["dom.require_user_interaction_for_beforeunload", false]],
     65  });
     66 
     67  let testTab = await BrowserTestUtils.openNewForegroundTab(
     68    gBrowser,
     69    TEST_PAGE,
     70    false,
     71    true
     72  );
     73  let browser = testTab.linkedBrowser;
     74  browser.addProgressListener(
     75    tabStateListener,
     76    Ci.nsIWebProgress.NOTIFY_STATE_WINDOW
     77  );
     78 
     79  const NUM_TESTS = 7;
     80  await SpecialPowers.spawn(browser, [NUM_TESTS], testCount => {
     81    let { testFns } = this.content.wrappedJSObject;
     82    Assert.equal(
     83      testFns.length,
     84      testCount,
     85      "Should have the correct number of test functions"
     86    );
     87  });
     88 
     89  for (let allowNavigation of [false, true]) {
     90    for (let i = 0; i < NUM_TESTS; i++) {
     91      info(
     92        `Running test ${i} with navigation ${
     93          allowNavigation ? "allowed" : "forbidden"
     94        }`
     95      );
     96 
     97      if (allowNavigation) {
     98        // If we're allowing navigations, we need to re-load the test
     99        // page after each test, since the tests will each navigate away
    100        // from it.
    101        await promiseLoaded(TEST_PAGE, () => {
    102          browser.loadURI(Services.io.newURI(TEST_PAGE), {
    103            triggeringPrincipal: document.nodePrincipal,
    104          });
    105        });
    106      }
    107 
    108      let promptPromise = promiseStayOnPagePrompt(browser, allowNavigation);
    109      let loadPromise;
    110      if (allowNavigation) {
    111        loadPromise = promiseLoaded(TARGETED_PAGE);
    112      }
    113 
    114      let winID = await SpecialPowers.spawn(
    115        browser,
    116        [i, TARGETED_PAGE],
    117        (testIdx, url) => {
    118          let { testFns } = this.content.wrappedJSObject;
    119          this.content.onbeforeunload = testFns[testIdx];
    120          this.content.location = url;
    121          return this.content.windowGlobalChild.innerWindowId;
    122        }
    123      );
    124 
    125      await promptPromise;
    126      await loadPromise;
    127 
    128      if (allowNavigation) {
    129        await SpecialPowers.spawn(
    130          browser,
    131          [TARGETED_PAGE, winID],
    132          (url, winID) => {
    133            this.content.onbeforeunload = null;
    134            Assert.equal(
    135              this.content.location.href,
    136              url,
    137              "Page should have navigated to the correct URL"
    138            );
    139            Assert.notEqual(
    140              this.content.windowGlobalChild.innerWindowId,
    141              winID,
    142              "Page should have a new inner window"
    143            );
    144          }
    145        );
    146      } else {
    147        await SpecialPowers.spawn(browser, [TEST_PAGE, winID], (url, winID) => {
    148          this.content.onbeforeunload = null;
    149          Assert.equal(
    150            this.content.location.href,
    151            url,
    152            "Page should have the same URL"
    153          );
    154          Assert.equal(
    155            this.content.windowGlobalChild.innerWindowId,
    156            winID,
    157            "Page should have the same inner window"
    158          );
    159        });
    160      }
    161    }
    162  }
    163 
    164  gBrowser.removeTab(testTab);
    165 });