tor-browser

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

browser_contentAreaClick.js (9818B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 /**
      6 * Test for bug 549340.
      7 * Test for browser.js::contentAreaClick() util.
      8 *
      9 * The test opens a new browser window, then replaces browser.js methods invoked
     10 * by contentAreaClick with a mock function that tracks which methods have been
     11 * called.
     12 * Each sub-test synthesizes a mouse click event on links injected in content,
     13 * the event is collected by a click handler that ensures that contentAreaClick
     14 * correctly prevent default events, and follows the correct code path.
     15 */
     16 
     17 const { sinon } = ChromeUtils.importESModule(
     18  "resource://testing-common/Sinon.sys.mjs"
     19 );
     20 
     21 var gTests = [
     22  {
     23    desc: "Simple left click",
     24    setup() {},
     25    clean() {},
     26    event: {},
     27    targets: ["commonlink", "mathlink", "svgxlink", "maplink"],
     28    expectedInvokedMethods: [],
     29    preventDefault: false,
     30  },
     31 
     32  {
     33    desc: "Ctrl/Cmd left click",
     34    setup() {},
     35    clean() {},
     36    event: { ctrlKey: true, metaKey: true },
     37    targets: ["commonlink", "mathlink", "svgxlink", "maplink"],
     38    expectedInvokedMethods: ["urlSecurityCheck", "openLinkIn"],
     39    preventDefault: true,
     40  },
     41 
     42  // The next test should just be like Alt click.
     43  {
     44    desc: "Shift+Alt left click",
     45    setup() {
     46      Services.prefs.setBoolPref("browser.altClickSave", true);
     47    },
     48    clean() {
     49      Services.prefs.clearUserPref("browser.altClickSave");
     50    },
     51    event: { shiftKey: true, altKey: true },
     52    targets: ["commonlink", "maplink"],
     53    expectedInvokedMethods: ["gatherTextUnder", "saveURL"],
     54    preventDefault: true,
     55  },
     56 
     57  {
     58    desc: "Shift+Alt left click on XLinks",
     59    setup() {
     60      Services.prefs.setBoolPref("browser.altClickSave", true);
     61    },
     62    clean() {
     63      Services.prefs.clearUserPref("browser.altClickSave");
     64    },
     65    event: { shiftKey: true, altKey: true },
     66    targets: ["mathlink", "svgxlink"],
     67    expectedInvokedMethods: ["saveURL"],
     68    preventDefault: true,
     69  },
     70 
     71  {
     72    desc: "Shift click",
     73    setup() {},
     74    clean() {},
     75    event: { shiftKey: true },
     76    targets: ["commonlink", "mathlink", "svgxlink", "maplink"],
     77    expectedInvokedMethods: ["urlSecurityCheck", "openLinkIn"],
     78    preventDefault: true,
     79  },
     80 
     81  {
     82    desc: "Alt click",
     83    setup() {
     84      Services.prefs.setBoolPref("browser.altClickSave", true);
     85    },
     86    clean() {
     87      Services.prefs.clearUserPref("browser.altClickSave");
     88    },
     89    event: { altKey: true },
     90    targets: ["commonlink", "maplink"],
     91    expectedInvokedMethods: ["gatherTextUnder", "saveURL"],
     92    preventDefault: true,
     93  },
     94 
     95  {
     96    desc: "Alt click on XLinks",
     97    setup() {
     98      Services.prefs.setBoolPref("browser.altClickSave", true);
     99    },
    100    clean() {
    101      Services.prefs.clearUserPref("browser.altClickSave");
    102    },
    103    event: { altKey: true },
    104    targets: ["mathlink", "svgxlink"],
    105    expectedInvokedMethods: ["saveURL"],
    106    preventDefault: true,
    107  },
    108 
    109  {
    110    desc: "Panel click",
    111    setup() {},
    112    clean() {},
    113    event: {},
    114    targets: ["panellink"],
    115    expectedInvokedMethods: ["urlSecurityCheck", "loadURI"],
    116    preventDefault: true,
    117  },
    118 
    119  {
    120    desc: "Simple middle click opentab",
    121    setup() {},
    122    clean() {},
    123    event: { button: 1 },
    124    wantedEvent: "auxclick",
    125    targets: ["commonlink", "mathlink", "svgxlink", "maplink"],
    126    expectedInvokedMethods: ["urlSecurityCheck", "openLinkIn"],
    127    preventDefault: true,
    128  },
    129 
    130  {
    131    desc: "Simple middle click openwin",
    132    setup() {
    133      Services.prefs.setBoolPref("browser.tabs.opentabfor.middleclick", false);
    134    },
    135    clean() {
    136      Services.prefs.clearUserPref("browser.tabs.opentabfor.middleclick");
    137    },
    138    event: { button: 1 },
    139    wantedEvent: "auxclick",
    140    targets: ["commonlink", "mathlink", "svgxlink", "maplink"],
    141    expectedInvokedMethods: ["urlSecurityCheck", "openLinkIn"],
    142    preventDefault: true,
    143  },
    144 
    145  {
    146    desc: "Middle mouse paste",
    147    setup() {
    148      Services.prefs.setBoolPref("middlemouse.contentLoadURL", true);
    149      Services.prefs.setBoolPref("general.autoScroll", false);
    150    },
    151    clean() {
    152      Services.prefs.clearUserPref("middlemouse.contentLoadURL");
    153      Services.prefs.clearUserPref("general.autoScroll");
    154    },
    155    event: { button: 1 },
    156    wantedEvent: "auxclick",
    157    targets: ["emptylink"],
    158    expectedInvokedMethods: ["middleMousePaste"],
    159    preventDefault: true,
    160  },
    161 ];
    162 
    163 // Array of method names that will be replaced in the new window.
    164 var gReplacedMethods = [
    165  "middleMousePaste",
    166  "urlSecurityCheck",
    167  "loadURI",
    168  "gatherTextUnder",
    169  "saveURL",
    170  "openLinkIn",
    171  "getShortcutOrURIAndPostData",
    172 ];
    173 
    174 // Returns the target object for the replaced method.
    175 function getStub(replacedMethod) {
    176  let targetObj =
    177    replacedMethod == "getShortcutOrURIAndPostData" ? UrlbarUtils : gTestWin;
    178  return targetObj[replacedMethod];
    179 }
    180 
    181 // Reference to the new window.
    182 var gTestWin = null;
    183 
    184 // The test currently running.
    185 var gCurrentTest = null;
    186 
    187 function test() {
    188  waitForExplicitFinish();
    189 
    190  registerCleanupFunction(function () {
    191    sinon.restore();
    192  });
    193 
    194  gTestWin = openDialog(location, "", "chrome,all,dialog=no", "about:blank");
    195  whenDelayedStartupFinished(gTestWin, function () {
    196    info("Browser window opened");
    197    waitForFocus(function () {
    198      info("Browser window focused");
    199      waitForFocus(
    200        function () {
    201          info("Setting up browser...");
    202          setupTestBrowserWindow();
    203          info("Running tests...");
    204          executeSoon(runNextTest);
    205        },
    206        gTestWin.content,
    207        true
    208      );
    209    }, gTestWin);
    210  });
    211 }
    212 
    213 // Click handler used to steal click events.
    214 var gClickHandler = {
    215  handleEvent(event) {
    216    if (event.type == "click" && event.button != 0) {
    217      return;
    218    }
    219    let linkId = event.target.id || event.target.localName;
    220    let wantedEvent = gCurrentTest.wantedEvent || "click";
    221    is(
    222      event.type,
    223      wantedEvent,
    224      `${gCurrentTest.desc}:Handler received a ${wantedEvent} event on ${linkId}`
    225    );
    226 
    227    let isPanelClick = linkId == "panellink";
    228    gTestWin.contentAreaClick(event, isPanelClick);
    229    let prevent = event.defaultPrevented;
    230    is(
    231      prevent,
    232      gCurrentTest.preventDefault,
    233      gCurrentTest.desc +
    234        ": event.defaultPrevented is correct (" +
    235        prevent +
    236        ")"
    237    );
    238 
    239    // Check that all required methods have been called.
    240    for (let expectedMethod of gCurrentTest.expectedInvokedMethods) {
    241      ok(
    242        getStub(expectedMethod).called,
    243        `${gCurrentTest.desc}:${expectedMethod} should have been invoked`
    244      );
    245    }
    246 
    247    for (let method of gReplacedMethods) {
    248      if (
    249        getStub(method).called &&
    250        !gCurrentTest.expectedInvokedMethods.includes(method)
    251      ) {
    252        ok(false, `Should have not called ${method}`);
    253      }
    254    }
    255 
    256    event.preventDefault();
    257    event.stopPropagation();
    258 
    259    executeSoon(runNextTest);
    260  },
    261 };
    262 
    263 function setupTestBrowserWindow() {
    264  // Steal click events and don't propagate them.
    265  gTestWin.addEventListener("click", gClickHandler, true);
    266  gTestWin.addEventListener("auxclick", gClickHandler, true);
    267 
    268  // Replace methods.
    269  gReplacedMethods.forEach(function (methodName) {
    270    let targetObj =
    271      methodName == "getShortcutOrURIAndPostData" ? UrlbarUtils : gTestWin;
    272    sinon.stub(targetObj, methodName).returnsArg(0);
    273  });
    274 
    275  // Inject links in content.
    276  let doc = gTestWin.content.document;
    277  let mainDiv = doc.createElement("div");
    278  mainDiv.innerHTML =
    279    '<p><a id="commonlink" href="http://mochi.test/moz/">Common link</a></p>' +
    280    '<p><a id="panellink" href="http://mochi.test/moz/">Panel link</a></p>' +
    281    '<p><a id="emptylink">Empty link</a></p>' +
    282    '<p><math id="mathlink" xmlns="http://www.w3.org/1998/Math/MathML" href="http://mochi.test/moz/"><mtext>MathML XLink</mtext></math></p>' +
    283    '<p><svg id="svgxlink" xmlns="http://www.w3.org/2000/svg" width="100px" height="50px" version="1.1"><a xlink:type="simple" xlink:href="http://mochi.test/moz/"><text transform="translate(10, 25)">SVG XLink</text></a></svg></p>' +
    284    '<p><map name="map" id="map"><area href="http://mochi.test/moz/" shape="rect" coords="0,0,128,128" /></map><img id="maplink" usemap="#map" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAIAAABMXPacAAAABGdBTUEAALGPC%2FxhBQAAAOtJREFUeF7t0IEAAAAAgKD9qRcphAoDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGBgwIAAAT0N51AAAAAASUVORK5CYII%3D"/></p>';
    285  doc.body.appendChild(mainDiv);
    286 }
    287 
    288 function runNextTest() {
    289  if (!gCurrentTest) {
    290    gCurrentTest = gTests.shift();
    291    gCurrentTest.setup();
    292  }
    293 
    294  if (!gCurrentTest.targets.length) {
    295    info(gCurrentTest.desc + ": cleaning up...");
    296    gCurrentTest.clean();
    297 
    298    if (gTests.length) {
    299      gCurrentTest = gTests.shift();
    300      gCurrentTest.setup();
    301    } else {
    302      finishTest();
    303      return;
    304    }
    305  }
    306 
    307  // Move to next target.
    308  sinon.resetHistory();
    309  let target = gCurrentTest.targets.shift();
    310 
    311  info(gCurrentTest.desc + ": testing " + target);
    312 
    313  // Fire (aux)click event.
    314  let targetElt = gTestWin.content.document.getElementById(target);
    315  ok(targetElt, gCurrentTest.desc + ": target is valid (" + targetElt.id + ")");
    316  EventUtils.synthesizeMouseAtCenter(
    317    targetElt,
    318    gCurrentTest.event,
    319    gTestWin.content
    320  );
    321 }
    322 
    323 function finishTest() {
    324  info("Restoring browser...");
    325  gTestWin.removeEventListener("click", gClickHandler, true);
    326  gTestWin.removeEventListener("auxclick", gClickHandler, true);
    327  gTestWin.close();
    328  finish();
    329 }