1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/base/content/test/general/browser_contentAreaClick.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,307 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/** 1.9 + * Test for bug 549340. 1.10 + * Test for browser.js::contentAreaClick() util. 1.11 + * 1.12 + * The test opens a new browser window, then replaces browser.js methods invoked 1.13 + * by contentAreaClick with a mock function that tracks which methods have been 1.14 + * called. 1.15 + * Each sub-test synthesizes a mouse click event on links injected in content, 1.16 + * the event is collected by a click handler that ensures that contentAreaClick 1.17 + * correctly prevent default events, and follows the correct code path. 1.18 + */ 1.19 + 1.20 +let gTests = [ 1.21 + 1.22 + { 1.23 + desc: "Simple left click", 1.24 + setup: function() {}, 1.25 + clean: function() {}, 1.26 + event: {}, 1.27 + targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ], 1.28 + expectedInvokedMethods: [], 1.29 + preventDefault: false, 1.30 + }, 1.31 + 1.32 + { 1.33 + desc: "Ctrl/Cmd left click", 1.34 + setup: function() {}, 1.35 + clean: function() {}, 1.36 + event: { ctrlKey: true, 1.37 + metaKey: true }, 1.38 + targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ], 1.39 + expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ], 1.40 + preventDefault: true, 1.41 + }, 1.42 + 1.43 + // The next test was once handling feedService.forcePreview(). Now it should 1.44 + // just be like Alt click. 1.45 + { 1.46 + desc: "Shift+Alt left click", 1.47 + setup: function() { 1.48 + gPrefService.setBoolPref("browser.altClickSave", true); 1.49 + }, 1.50 + clean: function() { 1.51 + gPrefService.clearUserPref("browser.altClickSave"); 1.52 + }, 1.53 + event: { shiftKey: true, 1.54 + altKey: true }, 1.55 + targets: [ "commonlink", "maplink" ], 1.56 + expectedInvokedMethods: [ "gatherTextUnder", "saveURL" ], 1.57 + preventDefault: true, 1.58 + }, 1.59 + 1.60 + { 1.61 + desc: "Shift+Alt left click on XLinks", 1.62 + setup: function() { 1.63 + gPrefService.setBoolPref("browser.altClickSave", true); 1.64 + }, 1.65 + clean: function() { 1.66 + gPrefService.clearUserPref("browser.altClickSave"); 1.67 + }, 1.68 + event: { shiftKey: true, 1.69 + altKey: true }, 1.70 + targets: [ "mathxlink", "svgxlink"], 1.71 + expectedInvokedMethods: [ "saveURL" ], 1.72 + preventDefault: true, 1.73 + }, 1.74 + 1.75 + { 1.76 + desc: "Shift click", 1.77 + setup: function() {}, 1.78 + clean: function() {}, 1.79 + event: { shiftKey: true }, 1.80 + targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ], 1.81 + expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ], 1.82 + preventDefault: true, 1.83 + }, 1.84 + 1.85 + { 1.86 + desc: "Alt click", 1.87 + setup: function() { 1.88 + gPrefService.setBoolPref("browser.altClickSave", true); 1.89 + }, 1.90 + clean: function() { 1.91 + gPrefService.clearUserPref("browser.altClickSave"); 1.92 + }, 1.93 + event: { altKey: true }, 1.94 + targets: [ "commonlink", "maplink" ], 1.95 + expectedInvokedMethods: [ "gatherTextUnder", "saveURL" ], 1.96 + preventDefault: true, 1.97 + }, 1.98 + 1.99 + { 1.100 + desc: "Alt click on XLinks", 1.101 + setup: function() { 1.102 + gPrefService.setBoolPref("browser.altClickSave", true); 1.103 + }, 1.104 + clean: function() { 1.105 + gPrefService.clearUserPref("browser.altClickSave"); 1.106 + }, 1.107 + event: { altKey: true }, 1.108 + targets: [ "mathxlink", "svgxlink" ], 1.109 + expectedInvokedMethods: [ "saveURL" ], 1.110 + preventDefault: true, 1.111 + }, 1.112 + 1.113 + { 1.114 + desc: "Panel click", 1.115 + setup: function() {}, 1.116 + clean: function() {}, 1.117 + event: {}, 1.118 + targets: [ "panellink" ], 1.119 + expectedInvokedMethods: [ "urlSecurityCheck", "loadURI" ], 1.120 + preventDefault: true, 1.121 + }, 1.122 + 1.123 + { 1.124 + desc: "Simple middle click opentab", 1.125 + setup: function() {}, 1.126 + clean: function() {}, 1.127 + event: { button: 1 }, 1.128 + targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ], 1.129 + expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ], 1.130 + preventDefault: true, 1.131 + }, 1.132 + 1.133 + { 1.134 + desc: "Simple middle click openwin", 1.135 + setup: function() { 1.136 + gPrefService.setBoolPref("browser.tabs.opentabfor.middleclick", false); 1.137 + }, 1.138 + clean: function() { 1.139 + gPrefService.clearUserPref("browser.tabs.opentabfor.middleclick"); 1.140 + }, 1.141 + event: { button: 1 }, 1.142 + targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ], 1.143 + expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ], 1.144 + preventDefault: true, 1.145 + }, 1.146 + 1.147 + { 1.148 + desc: "Middle mouse paste", 1.149 + setup: function() { 1.150 + gPrefService.setBoolPref("middlemouse.contentLoadURL", true); 1.151 + gPrefService.setBoolPref("general.autoScroll", false); 1.152 + }, 1.153 + clean: function() { 1.154 + gPrefService.clearUserPref("middlemouse.contentLoadURL"); 1.155 + gPrefService.clearUserPref("general.autoScroll"); 1.156 + }, 1.157 + event: { button: 1 }, 1.158 + targets: [ "emptylink" ], 1.159 + expectedInvokedMethods: [ "middleMousePaste" ], 1.160 + preventDefault: true, 1.161 + }, 1.162 + 1.163 +]; 1.164 + 1.165 +// Array of method names that will be replaced in the new window. 1.166 +let gReplacedMethods = [ 1.167 + "middleMousePaste", 1.168 + "urlSecurityCheck", 1.169 + "loadURI", 1.170 + "gatherTextUnder", 1.171 + "saveURL", 1.172 + "openLinkIn", 1.173 + "getShortcutOrURIAndPostData", 1.174 +]; 1.175 + 1.176 +// Reference to the new window. 1.177 +let gTestWin = null; 1.178 + 1.179 +// List of methods invoked by a specific call to contentAreaClick. 1.180 +let gInvokedMethods = []; 1.181 + 1.182 +// The test currently running. 1.183 +let gCurrentTest = null; 1.184 + 1.185 +function test() { 1.186 + waitForExplicitFinish(); 1.187 + 1.188 + gTestWin = openDialog(location, "", "chrome,all,dialog=no", "about:blank"); 1.189 + whenDelayedStartupFinished(gTestWin, function () { 1.190 + info("Browser window opened"); 1.191 + waitForFocus(function() { 1.192 + info("Browser window focused"); 1.193 + waitForFocus(function() { 1.194 + info("Setting up browser..."); 1.195 + setupTestBrowserWindow(); 1.196 + info("Running tests..."); 1.197 + executeSoon(runNextTest); 1.198 + }, gTestWin.content, true); 1.199 + }, gTestWin); 1.200 + }); 1.201 +} 1.202 + 1.203 +// Click handler used to steal click events. 1.204 +let gClickHandler = { 1.205 + handleEvent: function (event) { 1.206 + let linkId = event.target.id || event.target.localName; 1.207 + is(event.type, "click", 1.208 + gCurrentTest.desc + ":Handler received a click event on " + linkId); 1.209 + 1.210 + let isPanelClick = linkId == "panellink"; 1.211 + gTestWin.contentAreaClick(event, isPanelClick); 1.212 + let prevent = event.defaultPrevented; 1.213 + is(prevent, gCurrentTest.preventDefault, 1.214 + gCurrentTest.desc + ": event.defaultPrevented is correct (" + prevent + ")") 1.215 + 1.216 + // Check that all required methods have been called. 1.217 + gCurrentTest.expectedInvokedMethods.forEach(function(aExpectedMethodName) { 1.218 + isnot(gInvokedMethods.indexOf(aExpectedMethodName), -1, 1.219 + gCurrentTest.desc + ":" + aExpectedMethodName + " was invoked"); 1.220 + }); 1.221 + 1.222 + if (gInvokedMethods.length != gCurrentTest.expectedInvokedMethods.length) { 1.223 + ok(false, "Wrong number of invoked methods"); 1.224 + gInvokedMethods.forEach(function (method) info(method + " was invoked")); 1.225 + } 1.226 + 1.227 + event.preventDefault(); 1.228 + event.stopPropagation(); 1.229 + 1.230 + executeSoon(runNextTest); 1.231 + } 1.232 +} 1.233 + 1.234 +// Wraps around the methods' replacement mock function. 1.235 +function wrapperMethod(aInvokedMethods, aMethodName) { 1.236 + return function () { 1.237 + aInvokedMethods.push(aMethodName); 1.238 + // At least getShortcutOrURIAndPostData requires to return url 1.239 + return (aMethodName == "getShortcutOrURIAndPostData") ? arguments.url : arguments[0]; 1.240 + } 1.241 +} 1.242 + 1.243 +function setupTestBrowserWindow() { 1.244 + // Steal click events and don't propagate them. 1.245 + gTestWin.addEventListener("click", gClickHandler, true); 1.246 + 1.247 + // Replace methods. 1.248 + gReplacedMethods.forEach(function (aMethodName) { 1.249 + gTestWin["old_" + aMethodName] = gTestWin[aMethodName]; 1.250 + gTestWin[aMethodName] = wrapperMethod(gInvokedMethods, aMethodName); 1.251 + }); 1.252 + 1.253 + // Inject links in content. 1.254 + let doc = gTestWin.content.document; 1.255 + let mainDiv = doc.createElement("div"); 1.256 + mainDiv.innerHTML = 1.257 + '<p><a id="commonlink" href="http://mochi.test/moz/">Common link</a></p>' + 1.258 + '<p><a id="panellink" href="http://mochi.test/moz/">Panel link</a></p>' + 1.259 + '<p><a id="emptylink">Empty link</a></p>' + 1.260 + '<p><math id="mathxlink" xmlns="http://www.w3.org/1998/Math/MathML" xlink:type="simple" xlink:href="http://mochi.test/moz/"><mtext>MathML XLink</mtext></math></p>' + 1.261 + '<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>' + 1.262 + '<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>' 1.263 + doc.body.appendChild(mainDiv); 1.264 +} 1.265 + 1.266 +function runNextTest() { 1.267 + if (!gCurrentTest) { 1.268 + gCurrentTest = gTests.shift(); 1.269 + gCurrentTest.setup(); 1.270 + } 1.271 + 1.272 + if (gCurrentTest.targets.length == 0) { 1.273 + info(gCurrentTest.desc + ": cleaning up...") 1.274 + gCurrentTest.clean(); 1.275 + 1.276 + if (gTests.length > 0) { 1.277 + gCurrentTest = gTests.shift(); 1.278 + gCurrentTest.setup(); 1.279 + } 1.280 + else { 1.281 + finishTest(); 1.282 + return; 1.283 + } 1.284 + } 1.285 + 1.286 + // Move to next target. 1.287 + gInvokedMethods.length = 0; 1.288 + let target = gCurrentTest.targets.shift(); 1.289 + 1.290 + info(gCurrentTest.desc + ": testing " + target); 1.291 + 1.292 + // Fire click event. 1.293 + let targetElt = gTestWin.content.document.getElementById(target); 1.294 + ok(targetElt, gCurrentTest.desc + ": target is valid (" + targetElt.id + ")"); 1.295 + EventUtils.synthesizeMouseAtCenter(targetElt, gCurrentTest.event, gTestWin.content); 1.296 +} 1.297 + 1.298 +function finishTest() { 1.299 + info("Restoring browser..."); 1.300 + gTestWin.removeEventListener("click", gClickHandler, true); 1.301 + 1.302 + // Restore original methods. 1.303 + gReplacedMethods.forEach(function (aMethodName) { 1.304 + gTestWin[aMethodName] = gTestWin["old_" + aMethodName]; 1.305 + delete gTestWin["old_" + aMethodName]; 1.306 + }); 1.307 + 1.308 + gTestWin.close(); 1.309 + finish(); 1.310 +}