tor-browser

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

browser_backforward_userinteraction.js (11339B)


      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_PAGE =
      7  getRootDirectory(gTestPath).replace(
      8    "chrome://mochitests/content",
      9    "https://example.com"
     10  ) + "dummy_page.html";
     11 const IFRAME_PAGE =
     12  getRootDirectory(gTestPath).replace(
     13    "chrome://mochitests/content",
     14    "https://example.com"
     15  ) + "dummy_iframe_page.html";
     16 
     17 async function assertMenulist(entries, baseURL = TEST_PAGE) {
     18  // Wait for the session data to be flushed before continuing the test
     19  await new Promise(resolve =>
     20    SessionStore.getSessionHistory(gBrowser.selectedTab, resolve)
     21  );
     22 
     23  let backButton = document.getElementById("back-button");
     24  let contextMenu = document.getElementById("backForwardMenu");
     25 
     26  info("waiting for the history menu to open");
     27 
     28  let popupShownPromise = BrowserTestUtils.waitForEvent(
     29    contextMenu,
     30    "popupshown"
     31  );
     32  EventUtils.synthesizeMouseAtCenter(backButton, {
     33    type: "contextmenu",
     34    button: 2,
     35  });
     36  await popupShownPromise;
     37 
     38  ok(true, "history menu opened");
     39 
     40  let nodes = contextMenu.childNodes;
     41 
     42  is(
     43    nodes.length,
     44    entries.length,
     45    "Has the expected number of contextMenu entries"
     46  );
     47 
     48  for (let i = 0; i < entries.length; i++) {
     49    let node = nodes[i];
     50    is(
     51      node.getAttribute("uri").replace(/[?|#]/, "!"),
     52      baseURL + "!entry=" + entries[i],
     53      "contextMenu node has the correct uri"
     54    );
     55  }
     56 
     57  let popupHiddenPromise = BrowserTestUtils.waitForEvent(
     58    contextMenu,
     59    "popuphidden"
     60  );
     61  contextMenu.hidePopup();
     62  await popupHiddenPromise;
     63 }
     64 
     65 // There are different ways of loading a page, but they should exhibit roughly the same
     66 // back-forward behavior for the purpose of requiring user interaction. Thus, we
     67 // have a utility function that runs the same test with a parameterized method of loading
     68 // new URLs.
     69 async function runTopLevelTest(loadMethod, useHashes = false) {
     70  let p = useHashes ? "#" : "?";
     71 
     72  // Test with both pref on and off
     73  for (let requireUserInteraction of [true, false]) {
     74    Services.prefs.setBoolPref(
     75      "browser.navigation.requireUserInteraction",
     76      requireUserInteraction
     77    );
     78 
     79    let tab = await BrowserTestUtils.openNewForegroundTab(
     80      gBrowser,
     81      TEST_PAGE + p + "entry=0"
     82    );
     83    let browser = tab.linkedBrowser;
     84    // Add some user interaction to entry 0
     85    await BrowserTestUtils.synthesizeMouse(
     86      "body",
     87      0,
     88      0,
     89      {},
     90      browser.browsingContext,
     91      true
     92    );
     93 
     94    assertBackForwardState(false, false);
     95 
     96    await loadMethod(TEST_PAGE + p + "entry=1");
     97 
     98    assertBackForwardState(true, false);
     99    await assertMenulist([1, 0]);
    100 
    101    await loadMethod(TEST_PAGE + p + "entry=2");
    102 
    103    assertBackForwardState(true, false);
    104    await assertMenulist(requireUserInteraction ? [2, 0] : [2, 1, 0]);
    105 
    106    await loadMethod(TEST_PAGE + p + "entry=3");
    107 
    108    info("Adding user interaction for entry=3");
    109    // Add some user interaction to entry 3
    110    await BrowserTestUtils.synthesizeMouse(
    111      "body",
    112      0,
    113      0,
    114      {},
    115      browser.browsingContext,
    116      true
    117    );
    118 
    119    assertBackForwardState(true, false);
    120    await assertMenulist(requireUserInteraction ? [3, 0] : [3, 2, 1, 0]);
    121 
    122    await loadMethod(TEST_PAGE + p + "entry=4");
    123 
    124    assertBackForwardState(true, false);
    125    await assertMenulist(requireUserInteraction ? [4, 3, 0] : [4, 3, 2, 1, 0]);
    126 
    127    info("Adding user interaction for entry=4");
    128    // Add some user interaction to entry 4
    129    await BrowserTestUtils.synthesizeMouse(
    130      "body",
    131      0,
    132      0,
    133      {},
    134      browser.browsingContext,
    135      true
    136    );
    137 
    138    await loadMethod(TEST_PAGE + p + "entry=5");
    139 
    140    assertBackForwardState(true, false);
    141    await assertMenulist(
    142      requireUserInteraction ? [5, 4, 3, 0] : [5, 4, 3, 2, 1, 0]
    143    );
    144 
    145    await goBack(TEST_PAGE + p + "entry=4");
    146    await goBack(TEST_PAGE + p + "entry=3");
    147 
    148    if (!requireUserInteraction) {
    149      await goBack(TEST_PAGE + p + "entry=2");
    150      await goBack(TEST_PAGE + p + "entry=1");
    151    }
    152 
    153    assertBackForwardState(true, true);
    154    await assertMenulist(
    155      requireUserInteraction ? [5, 4, 3, 0] : [5, 4, 3, 2, 1, 0]
    156    );
    157 
    158    await goBack(TEST_PAGE + p + "entry=0");
    159 
    160    assertBackForwardState(false, true);
    161 
    162    if (!requireUserInteraction) {
    163      await goForward(TEST_PAGE + p + "entry=1");
    164      await goForward(TEST_PAGE + p + "entry=2");
    165    }
    166 
    167    await goForward(TEST_PAGE + p + "entry=3");
    168 
    169    assertBackForwardState(true, true);
    170    await assertMenulist(
    171      requireUserInteraction ? [5, 4, 3, 0] : [5, 4, 3, 2, 1, 0]
    172    );
    173 
    174    await goForward(TEST_PAGE + p + "entry=4");
    175 
    176    assertBackForwardState(true, true);
    177    await assertMenulist(
    178      requireUserInteraction ? [5, 4, 3, 0] : [5, 4, 3, 2, 1, 0]
    179    );
    180 
    181    await goForward(TEST_PAGE + p + "entry=5");
    182 
    183    assertBackForwardState(true, false);
    184    await assertMenulist(
    185      requireUserInteraction ? [5, 4, 3, 0] : [5, 4, 3, 2, 1, 0]
    186    );
    187 
    188    BrowserTestUtils.removeTab(tab);
    189  }
    190 
    191  Services.prefs.clearUserPref("browser.navigation.requireUserInteraction");
    192 }
    193 
    194 async function runIframeTest(loadMethod) {
    195  // Test with both pref on and off
    196  for (let requireUserInteraction of [true, false]) {
    197    Services.prefs.setBoolPref(
    198      "browser.navigation.requireUserInteraction",
    199      requireUserInteraction
    200    );
    201 
    202    // First test the boring case where we only have one iframe.
    203    let tab = await BrowserTestUtils.openNewForegroundTab(
    204      gBrowser,
    205      IFRAME_PAGE + "?entry=0"
    206    );
    207    let browser = tab.linkedBrowser;
    208    // Add some user interaction to entry 0
    209    await BrowserTestUtils.synthesizeMouse(
    210      "body",
    211      0,
    212      0,
    213      {},
    214      browser.browsingContext,
    215      true
    216    );
    217 
    218    assertBackForwardState(false, false);
    219 
    220    await loadMethod(TEST_PAGE + "?sub_entry=1", "frame1");
    221 
    222    assertBackForwardState(true, false);
    223    await assertMenulist([0, 0], IFRAME_PAGE);
    224 
    225    await loadMethod(TEST_PAGE + "?sub_entry=2", "frame1");
    226 
    227    assertBackForwardState(true, false);
    228    await assertMenulist(
    229      requireUserInteraction ? [0, 0] : [0, 0, 0],
    230      IFRAME_PAGE
    231    );
    232 
    233    let bc = await SpecialPowers.spawn(browser, [], function () {
    234      return content.document.getElementById("frame1").browsingContext;
    235    });
    236 
    237    // Add some user interaction to sub entry 2
    238    await BrowserTestUtils.synthesizeMouse("body", 0, 0, {}, bc, true);
    239 
    240    await loadMethod(TEST_PAGE + "?sub_entry=3", "frame1");
    241 
    242    assertBackForwardState(true, false);
    243    await assertMenulist(
    244      requireUserInteraction ? [0, 0, 0] : [0, 0, 0, 0],
    245      IFRAME_PAGE
    246    );
    247 
    248    await loadMethod(TEST_PAGE + "?sub_entry=4", "frame1");
    249 
    250    assertBackForwardState(true, false);
    251    await assertMenulist(
    252      requireUserInteraction ? [0, 0, 0] : [0, 0, 0, 0, 0],
    253      IFRAME_PAGE
    254    );
    255 
    256    if (!requireUserInteraction) {
    257      await goBack(TEST_PAGE + "?sub_entry=3", true);
    258    }
    259 
    260    await goBack(TEST_PAGE + "?sub_entry=2", true);
    261 
    262    assertBackForwardState(true, true);
    263    await assertMenulist(
    264      requireUserInteraction ? [0, 0, 0] : [0, 0, 0, 0, 0],
    265      IFRAME_PAGE
    266    );
    267 
    268    await loadMethod(IFRAME_PAGE + "?entry=1");
    269 
    270    assertBackForwardState(true, false);
    271    await assertMenulist(
    272      requireUserInteraction ? [1, 0, 0] : [1, 0, 0, 0],
    273      IFRAME_PAGE
    274    );
    275 
    276    BrowserTestUtils.removeTab(tab);
    277 
    278    // Two iframes, now we're talking.
    279    tab = await BrowserTestUtils.openNewForegroundTab(
    280      gBrowser,
    281      IFRAME_PAGE + "?entry=0"
    282    );
    283    browser = tab.linkedBrowser;
    284    // Add some user interaction to entry 0
    285    await BrowserTestUtils.synthesizeMouse(
    286      "body",
    287      0,
    288      0,
    289      {},
    290      browser.browsingContext,
    291      true
    292    );
    293 
    294    await loadMethod(IFRAME_PAGE + "?entry=1");
    295 
    296    assertBackForwardState(true, false);
    297    await assertMenulist(requireUserInteraction ? [1, 0] : [1, 0], IFRAME_PAGE);
    298 
    299    // Add some user interaction to frame 1.
    300    bc = await SpecialPowers.spawn(browser, [], function () {
    301      return content.document.getElementById("frame1").browsingContext;
    302    });
    303    await BrowserTestUtils.synthesizeMouse("body", 0, 0, {}, bc, true);
    304 
    305    // Add some user interaction to frame 2.
    306    bc = await SpecialPowers.spawn(browser, [], function () {
    307      return content.document.getElementById("frame2").browsingContext;
    308    });
    309    await BrowserTestUtils.synthesizeMouse("body", 0, 0, {}, bc, true);
    310 
    311    // Navigate frame 2.
    312    await loadMethod(TEST_PAGE + "?sub_entry=1", "frame2");
    313 
    314    assertBackForwardState(true, false);
    315    await assertMenulist(
    316      requireUserInteraction ? [1, 1, 0] : [1, 1, 0],
    317      IFRAME_PAGE
    318    );
    319 
    320    // Add some user interaction to frame 1, again.
    321    bc = await SpecialPowers.spawn(browser, [], function () {
    322      return content.document.getElementById("frame1").browsingContext;
    323    });
    324    await BrowserTestUtils.synthesizeMouse("body", 0, 0, {}, bc, true);
    325 
    326    // Navigate frame 2, again.
    327    await loadMethod(TEST_PAGE + "?sub_entry=2", "frame2");
    328 
    329    assertBackForwardState(true, false);
    330    await assertMenulist(
    331      requireUserInteraction ? [1, 1, 1, 0] : [1, 1, 1, 0],
    332      IFRAME_PAGE
    333    );
    334 
    335    await goBack(TEST_PAGE + "?sub_entry=1", true);
    336 
    337    assertBackForwardState(true, true);
    338    await assertMenulist(
    339      requireUserInteraction ? [1, 1, 1, 0] : [1, 1, 1, 0],
    340      IFRAME_PAGE
    341    );
    342 
    343    await goBack(TEST_PAGE + "?sub_entry=0", true);
    344 
    345    assertBackForwardState(true, true);
    346    await assertMenulist(
    347      requireUserInteraction ? [1, 1, 1, 0] : [1, 1, 1, 0],
    348      IFRAME_PAGE
    349    );
    350 
    351    BrowserTestUtils.removeTab(tab);
    352  }
    353 
    354  Services.prefs.clearUserPref("browser.navigation.requireUserInteraction");
    355 }
    356 
    357 // Test that when the pref is flipped, we are skipping history
    358 // entries without user interaction when following links with hash URIs.
    359 add_task(async function test_hashURI() {
    360  async function followLinkHash(url) {
    361    info(`Creating and following a link to ${url}`);
    362    let browser = gBrowser.selectedBrowser;
    363    let loaded = BrowserTestUtils.waitForLocationChange(gBrowser, url);
    364    await SpecialPowers.spawn(browser, [url], function (url) {
    365      let a = content.document.createElement("a");
    366      a.href = url;
    367      content.document.body.appendChild(a);
    368      a.click();
    369    });
    370    await loaded;
    371    info(`Loaded ${url}`);
    372  }
    373 
    374  await runTopLevelTest(followLinkHash, true);
    375 });
    376 
    377 // Test that when the pref is flipped, we are skipping history
    378 // entries without user interaction when using history.pushState.
    379 add_task(async function test_pushState() {
    380  await runTopLevelTest(pushState);
    381 });
    382 
    383 // Test that when the pref is flipped, we are skipping history
    384 // entries without user interaction when following a link.
    385 add_task(async function test_followLink() {
    386  await runTopLevelTest(followLink);
    387 });
    388 
    389 // Test that when the pref is flipped, we are skipping history
    390 // entries without user interaction when navigating inside an iframe
    391 // using history.pushState.
    392 add_task(async function test_iframe_pushState() {
    393  await runIframeTest(pushState);
    394 });
    395 
    396 // Test that when the pref is flipped, we are skipping history
    397 // entries without user interaction when navigating inside an iframe
    398 // by following links.
    399 add_task(async function test_iframe_followLink() {
    400  await runIframeTest(followLink);
    401 });