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/. */
7 * Test for browser.js::contentAreaClick() util.
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
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.
20 desc: "Simple left click",
24 targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ],
25 expectedInvokedMethods: [],
26 preventDefault: false,
30 desc: "Ctrl/Cmd left click",
33 event: { ctrlKey: true,
35 targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ],
36 expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
40 // The next test was once handling feedService.forcePreview(). Now it should
41 // just be like Alt click.
43 desc: "Shift+Alt left click",
45 gPrefService.setBoolPref("browser.altClickSave", true);
48 gPrefService.clearUserPref("browser.altClickSave");
50 event: { shiftKey: true,
52 targets: [ "commonlink", "maplink" ],
53 expectedInvokedMethods: [ "gatherTextUnder", "saveURL" ],
58 desc: "Shift+Alt left click on XLinks",
60 gPrefService.setBoolPref("browser.altClickSave", true);
63 gPrefService.clearUserPref("browser.altClickSave");
65 event: { shiftKey: true,
67 targets: [ "mathxlink", "svgxlink"],
68 expectedInvokedMethods: [ "saveURL" ],
76 event: { shiftKey: true },
77 targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ],
78 expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
85 gPrefService.setBoolPref("browser.altClickSave", true);
88 gPrefService.clearUserPref("browser.altClickSave");
90 event: { altKey: true },
91 targets: [ "commonlink", "maplink" ],
92 expectedInvokedMethods: [ "gatherTextUnder", "saveURL" ],
97 desc: "Alt click on XLinks",
99 gPrefService.setBoolPref("browser.altClickSave", true);
102 gPrefService.clearUserPref("browser.altClickSave");
104 event: { altKey: true },
105 targets: [ "mathxlink", "svgxlink" ],
106 expectedInvokedMethods: [ "saveURL" ],
107 preventDefault: true,
112 setup: function() {},
113 clean: function() {},
115 targets: [ "panellink" ],
116 expectedInvokedMethods: [ "urlSecurityCheck", "loadURI" ],
117 preventDefault: true,
121 desc: "Simple middle click opentab",
122 setup: function() {},
123 clean: function() {},
124 event: { button: 1 },
125 targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ],
126 expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
127 preventDefault: true,
131 desc: "Simple middle click openwin",
133 gPrefService.setBoolPref("browser.tabs.opentabfor.middleclick", false);
136 gPrefService.clearUserPref("browser.tabs.opentabfor.middleclick");
138 event: { button: 1 },
139 targets: [ "commonlink", "mathxlink", "svgxlink", "maplink" ],
140 expectedInvokedMethods: [ "urlSecurityCheck", "openLinkIn" ],
141 preventDefault: true,
145 desc: "Middle mouse paste",
147 gPrefService.setBoolPref("middlemouse.contentLoadURL", true);
148 gPrefService.setBoolPref("general.autoScroll", false);
151 gPrefService.clearUserPref("middlemouse.contentLoadURL");
152 gPrefService.clearUserPref("general.autoScroll");
154 event: { button: 1 },
155 targets: [ "emptylink" ],
156 expectedInvokedMethods: [ "middleMousePaste" ],
157 preventDefault: true,
162 // Array of method names that will be replaced in the new window.
163 let gReplacedMethods = [
173 // Reference to the new window.
176 // List of methods invoked by a specific call to contentAreaClick.
177 let gInvokedMethods = [];
179 // The test currently running.
180 let gCurrentTest = null;
183 waitForExplicitFinish();
185 gTestWin = openDialog(location, "", "chrome,all,dialog=no", "about:blank");
186 whenDelayedStartupFinished(gTestWin, function () {
187 info("Browser window opened");
188 waitForFocus(function() {
189 info("Browser window focused");
190 waitForFocus(function() {
191 info("Setting up browser...");
192 setupTestBrowserWindow();
193 info("Running tests...");
194 executeSoon(runNextTest);
195 }, gTestWin.content, true);
200 // Click handler used to steal click events.
201 let gClickHandler = {
202 handleEvent: function (event) {
203 let linkId = event.target.id || event.target.localName;
204 is(event.type, "click",
205 gCurrentTest.desc + ":Handler received a click event on " + linkId);
207 let isPanelClick = linkId == "panellink";
208 gTestWin.contentAreaClick(event, isPanelClick);
209 let prevent = event.defaultPrevented;
210 is(prevent, gCurrentTest.preventDefault,
211 gCurrentTest.desc + ": event.defaultPrevented is correct (" + prevent + ")")
213 // Check that all required methods have been called.
214 gCurrentTest.expectedInvokedMethods.forEach(function(aExpectedMethodName) {
215 isnot(gInvokedMethods.indexOf(aExpectedMethodName), -1,
216 gCurrentTest.desc + ":" + aExpectedMethodName + " was invoked");
219 if (gInvokedMethods.length != gCurrentTest.expectedInvokedMethods.length) {
220 ok(false, "Wrong number of invoked methods");
221 gInvokedMethods.forEach(function (method) info(method + " was invoked"));
224 event.preventDefault();
225 event.stopPropagation();
227 executeSoon(runNextTest);
231 // Wraps around the methods' replacement mock function.
232 function wrapperMethod(aInvokedMethods, aMethodName) {
234 aInvokedMethods.push(aMethodName);
235 // At least getShortcutOrURI requires to return url that is the first param.
240 function setupTestBrowserWindow() {
241 // Steal click events and don't propagate them.
242 gTestWin.addEventListener("click", gClickHandler, true);
245 gReplacedMethods.forEach(function (aMethodName) {
246 gTestWin["old_" + aMethodName] = gTestWin[aMethodName];
247 gTestWin[aMethodName] = wrapperMethod(gInvokedMethods, aMethodName);
250 // Inject links in content.
251 let doc = gTestWin.content.document;
252 let mainDiv = doc.createElement("div");
254 '<p><a id="commonlink" href="http://mochi.test/moz/">Common link</a></p>' +
255 '<p><a id="panellink" href="http://mochi.test/moz/">Panel link</a></p>' +
256 '<p><a id="emptylink">Empty link</a></p>' +
257 '<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>' +
258 '<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>' +
259 '<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>'
260 doc.body.appendChild(mainDiv);
263 function runNextTest() {
265 gCurrentTest = gTests.shift();
266 gCurrentTest.setup();
269 if (gCurrentTest.targets.length == 0) {
270 info(gCurrentTest.desc + ": cleaning up...")
271 gCurrentTest.clean();
273 if (gTests.length > 0) {
274 gCurrentTest = gTests.shift();
275 gCurrentTest.setup();
283 // Move to next target.
284 gInvokedMethods.length = 0;
285 let target = gCurrentTest.targets.shift();
287 info(gCurrentTest.desc + ": testing " + target);
290 let targetElt = gTestWin.content.document.getElementById(target);
291 ok(targetElt, gCurrentTest.desc + ": target is valid (" + targetElt.id + ")");
292 EventUtils.synthesizeMouseAtCenter(targetElt, gCurrentTest.event, gTestWin.content);
295 function finishTest() {
296 info("Restoring browser...");
297 gTestWin.removeEventListener("click", gClickHandler, true);
299 // Restore original methods.
300 gReplacedMethods.forEach(function (aMethodName) {
301 gTestWin[aMethodName] = gTestWin["old_" + aMethodName];
302 delete gTestWin["old_" + aMethodName];