browser/base/content/test/general/head.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
michael@0 2
michael@0 3 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
michael@0 4 "resource://gre/modules/Promise.jsm");
michael@0 5 XPCOMUtils.defineLazyModuleGetter(this, "Task",
michael@0 6 "resource://gre/modules/Task.jsm");
michael@0 7 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
michael@0 8 "resource://gre/modules/PlacesUtils.jsm");
michael@0 9
michael@0 10 function whenDelayedStartupFinished(aWindow, aCallback) {
michael@0 11 Services.obs.addObserver(function observer(aSubject, aTopic) {
michael@0 12 if (aWindow == aSubject) {
michael@0 13 Services.obs.removeObserver(observer, aTopic);
michael@0 14 executeSoon(aCallback);
michael@0 15 }
michael@0 16 }, "browser-delayed-startup-finished", false);
michael@0 17 }
michael@0 18
michael@0 19 function findChromeWindowByURI(aURI) {
michael@0 20 let windows = Services.wm.getEnumerator(null);
michael@0 21 while (windows.hasMoreElements()) {
michael@0 22 let win = windows.getNext();
michael@0 23 if (win.location.href == aURI)
michael@0 24 return win;
michael@0 25 }
michael@0 26 return null;
michael@0 27 }
michael@0 28
michael@0 29 function updateTabContextMenu(tab) {
michael@0 30 let menu = document.getElementById("tabContextMenu");
michael@0 31 if (!tab)
michael@0 32 tab = gBrowser.selectedTab;
michael@0 33 var evt = new Event("");
michael@0 34 tab.dispatchEvent(evt);
michael@0 35 menu.openPopup(tab, "end_after", 0, 0, true, false, evt);
michael@0 36 is(TabContextMenu.contextTab, tab, "TabContextMenu context is the expected tab");
michael@0 37 menu.hidePopup();
michael@0 38 }
michael@0 39
michael@0 40 function openToolbarCustomizationUI(aCallback, aBrowserWin) {
michael@0 41 if (!aBrowserWin)
michael@0 42 aBrowserWin = window;
michael@0 43
michael@0 44 aBrowserWin.gCustomizeMode.enter();
michael@0 45
michael@0 46 aBrowserWin.gNavToolbox.addEventListener("customizationready", function UI_loaded() {
michael@0 47 aBrowserWin.gNavToolbox.removeEventListener("customizationready", UI_loaded);
michael@0 48 executeSoon(function() {
michael@0 49 aCallback(aBrowserWin)
michael@0 50 });
michael@0 51 });
michael@0 52 }
michael@0 53
michael@0 54 function closeToolbarCustomizationUI(aCallback, aBrowserWin) {
michael@0 55 aBrowserWin.gNavToolbox.addEventListener("aftercustomization", function unloaded() {
michael@0 56 aBrowserWin.gNavToolbox.removeEventListener("aftercustomization", unloaded);
michael@0 57 executeSoon(aCallback);
michael@0 58 });
michael@0 59
michael@0 60 aBrowserWin.gCustomizeMode.exit();
michael@0 61 }
michael@0 62
michael@0 63 function waitForCondition(condition, nextTest, errorMsg) {
michael@0 64 var tries = 0;
michael@0 65 var interval = setInterval(function() {
michael@0 66 if (tries >= 30) {
michael@0 67 ok(false, errorMsg);
michael@0 68 moveOn();
michael@0 69 }
michael@0 70 var conditionPassed;
michael@0 71 try {
michael@0 72 conditionPassed = condition();
michael@0 73 } catch (e) {
michael@0 74 ok(false, e + "\n" + e.stack);
michael@0 75 conditionPassed = false;
michael@0 76 }
michael@0 77 if (conditionPassed) {
michael@0 78 moveOn();
michael@0 79 }
michael@0 80 tries++;
michael@0 81 }, 100);
michael@0 82 var moveOn = function() { clearInterval(interval); nextTest(); };
michael@0 83 }
michael@0 84
michael@0 85 function getTestPlugin(aName) {
michael@0 86 var pluginName = aName || "Test Plug-in";
michael@0 87 var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
michael@0 88 var tags = ph.getPluginTags();
michael@0 89
michael@0 90 // Find the test plugin
michael@0 91 for (var i = 0; i < tags.length; i++) {
michael@0 92 if (tags[i].name == pluginName)
michael@0 93 return tags[i];
michael@0 94 }
michael@0 95 ok(false, "Unable to find plugin");
michael@0 96 return null;
michael@0 97 }
michael@0 98
michael@0 99 // call this to set the test plugin(s) initially expected enabled state.
michael@0 100 // it will automatically be reset to it's previous value after the test
michael@0 101 // ends
michael@0 102 function setTestPluginEnabledState(newEnabledState, pluginName) {
michael@0 103 var plugin = getTestPlugin(pluginName);
michael@0 104 var oldEnabledState = plugin.enabledState;
michael@0 105 plugin.enabledState = newEnabledState;
michael@0 106 SimpleTest.registerCleanupFunction(function() {
michael@0 107 getTestPlugin(pluginName).enabledState = oldEnabledState;
michael@0 108 });
michael@0 109 }
michael@0 110
michael@0 111 // after a test is done using the plugin doorhanger, we should just clear
michael@0 112 // any permissions that may have crept in
michael@0 113 function clearAllPluginPermissions() {
michael@0 114 let perms = Services.perms.enumerator;
michael@0 115 while (perms.hasMoreElements()) {
michael@0 116 let perm = perms.getNext();
michael@0 117 if (perm.type.startsWith('plugin')) {
michael@0 118 Services.perms.remove(perm.host, perm.type);
michael@0 119 }
michael@0 120 }
michael@0 121 }
michael@0 122
michael@0 123 function updateBlocklist(aCallback) {
michael@0 124 var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
michael@0 125 .getService(Ci.nsITimerCallback);
michael@0 126 var observer = function() {
michael@0 127 Services.obs.removeObserver(observer, "blocklist-updated");
michael@0 128 SimpleTest.executeSoon(aCallback);
michael@0 129 };
michael@0 130 Services.obs.addObserver(observer, "blocklist-updated", false);
michael@0 131 blocklistNotifier.notify(null);
michael@0 132 }
michael@0 133
michael@0 134 var _originalTestBlocklistURL = null;
michael@0 135 function setAndUpdateBlocklist(aURL, aCallback) {
michael@0 136 if (!_originalTestBlocklistURL)
michael@0 137 _originalTestBlocklistURL = Services.prefs.getCharPref("extensions.blocklist.url");
michael@0 138 Services.prefs.setCharPref("extensions.blocklist.url", aURL);
michael@0 139 updateBlocklist(aCallback);
michael@0 140 }
michael@0 141
michael@0 142 function resetBlocklist() {
michael@0 143 Services.prefs.setCharPref("extensions.blocklist.url", _originalTestBlocklistURL);
michael@0 144 }
michael@0 145
michael@0 146 function whenNewWindowLoaded(aOptions, aCallback) {
michael@0 147 let win = OpenBrowserWindow(aOptions);
michael@0 148 win.addEventListener("load", function onLoad() {
michael@0 149 win.removeEventListener("load", onLoad, false);
michael@0 150 aCallback(win);
michael@0 151 }, false);
michael@0 152 }
michael@0 153
michael@0 154 /**
michael@0 155 * Waits for all pending async statements on the default connection, before
michael@0 156 * proceeding with aCallback.
michael@0 157 *
michael@0 158 * @param aCallback
michael@0 159 * Function to be called when done.
michael@0 160 * @param aScope
michael@0 161 * Scope for the callback.
michael@0 162 * @param aArguments
michael@0 163 * Arguments array for the callback.
michael@0 164 *
michael@0 165 * @note The result is achieved by asynchronously executing a query requiring
michael@0 166 * a write lock. Since all statements on the same connection are
michael@0 167 * serialized, the end of this write operation means that all writes are
michael@0 168 * complete. Note that WAL makes so that writers don't block readers, but
michael@0 169 * this is a problem only across different connections.
michael@0 170 */
michael@0 171 function waitForAsyncUpdates(aCallback, aScope, aArguments) {
michael@0 172 let scope = aScope || this;
michael@0 173 let args = aArguments || [];
michael@0 174 let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
michael@0 175 .DBConnection;
michael@0 176 let begin = db.createAsyncStatement("BEGIN EXCLUSIVE");
michael@0 177 begin.executeAsync();
michael@0 178 begin.finalize();
michael@0 179
michael@0 180 let commit = db.createAsyncStatement("COMMIT");
michael@0 181 commit.executeAsync({
michael@0 182 handleResult: function() {},
michael@0 183 handleError: function() {},
michael@0 184 handleCompletion: function(aReason) {
michael@0 185 aCallback.apply(scope, args);
michael@0 186 }
michael@0 187 });
michael@0 188 commit.finalize();
michael@0 189 }
michael@0 190
michael@0 191 /**
michael@0 192 * Asynchronously check a url is visited.
michael@0 193
michael@0 194 * @param aURI The URI.
michael@0 195 * @param aExpectedValue The expected value.
michael@0 196 * @return {Promise}
michael@0 197 * @resolves When the check has been added successfully.
michael@0 198 * @rejects JavaScript exception.
michael@0 199 */
michael@0 200 function promiseIsURIVisited(aURI, aExpectedValue) {
michael@0 201 let deferred = Promise.defer();
michael@0 202 PlacesUtils.asyncHistory.isURIVisited(aURI, function(aURI, aIsVisited) {
michael@0 203 deferred.resolve(aIsVisited);
michael@0 204 });
michael@0 205
michael@0 206 return deferred.promise;
michael@0 207 }
michael@0 208
michael@0 209 function whenNewTabLoaded(aWindow, aCallback) {
michael@0 210 aWindow.BrowserOpenTab();
michael@0 211
michael@0 212 let browser = aWindow.gBrowser.selectedBrowser;
michael@0 213 if (browser.contentDocument.readyState === "complete") {
michael@0 214 aCallback();
michael@0 215 return;
michael@0 216 }
michael@0 217
michael@0 218 whenTabLoaded(aWindow.gBrowser.selectedTab, aCallback);
michael@0 219 }
michael@0 220
michael@0 221 function whenTabLoaded(aTab, aCallback) {
michael@0 222 let browser = aTab.linkedBrowser;
michael@0 223 browser.addEventListener("load", function onLoad() {
michael@0 224 browser.removeEventListener("load", onLoad, true);
michael@0 225 executeSoon(aCallback);
michael@0 226 }, true);
michael@0 227 }
michael@0 228
michael@0 229 function addVisits(aPlaceInfo, aCallback) {
michael@0 230 let places = [];
michael@0 231 if (aPlaceInfo instanceof Ci.nsIURI) {
michael@0 232 places.push({ uri: aPlaceInfo });
michael@0 233 } else if (Array.isArray(aPlaceInfo)) {
michael@0 234 places = places.concat(aPlaceInfo);
michael@0 235 } else {
michael@0 236 places.push(aPlaceInfo);
michael@0 237 }
michael@0 238
michael@0 239 // Create mozIVisitInfo for each entry.
michael@0 240 let now = Date.now();
michael@0 241 for (let i = 0; i < places.length; i++) {
michael@0 242 if (!places[i].title) {
michael@0 243 places[i].title = "test visit for " + places[i].uri.spec;
michael@0 244 }
michael@0 245 places[i].visits = [{
michael@0 246 transitionType: places[i].transition === undefined ? Ci.nsINavHistoryService.TRANSITION_LINK
michael@0 247 : places[i].transition,
michael@0 248 visitDate: places[i].visitDate || (now++) * 1000,
michael@0 249 referrerURI: places[i].referrer
michael@0 250 }];
michael@0 251 }
michael@0 252
michael@0 253 PlacesUtils.asyncHistory.updatePlaces(
michael@0 254 places,
michael@0 255 {
michael@0 256 handleError: function AAV_handleError() {
michael@0 257 throw("Unexpected error in adding visit.");
michael@0 258 },
michael@0 259 handleResult: function () {},
michael@0 260 handleCompletion: function UP_handleCompletion() {
michael@0 261 if (aCallback)
michael@0 262 aCallback();
michael@0 263 }
michael@0 264 }
michael@0 265 );
michael@0 266 }
michael@0 267
michael@0 268 /**
michael@0 269 * Ensures that the specified URIs are either cleared or not.
michael@0 270 *
michael@0 271 * @param aURIs
michael@0 272 * Array of page URIs
michael@0 273 * @param aShouldBeCleared
michael@0 274 * True if each visit to the URI should be cleared, false otherwise
michael@0 275 */
michael@0 276 function promiseHistoryClearedState(aURIs, aShouldBeCleared) {
michael@0 277 let deferred = Promise.defer();
michael@0 278 let callbackCount = 0;
michael@0 279 let niceStr = aShouldBeCleared ? "no longer" : "still";
michael@0 280 function callbackDone() {
michael@0 281 if (++callbackCount == aURIs.length)
michael@0 282 deferred.resolve();
michael@0 283 }
michael@0 284 aURIs.forEach(function (aURI) {
michael@0 285 PlacesUtils.asyncHistory.isURIVisited(aURI, function(aURI, aIsVisited) {
michael@0 286 is(aIsVisited, !aShouldBeCleared,
michael@0 287 "history visit " + aURI.spec + " should " + niceStr + " exist");
michael@0 288 callbackDone();
michael@0 289 });
michael@0 290 });
michael@0 291
michael@0 292 return deferred.promise;
michael@0 293 }
michael@0 294
michael@0 295 /**
michael@0 296 * Allows waiting for an observer notification once.
michael@0 297 *
michael@0 298 * @param topic
michael@0 299 * Notification topic to observe.
michael@0 300 *
michael@0 301 * @return {Promise}
michael@0 302 * @resolves The array [subject, data] from the observed notification.
michael@0 303 * @rejects Never.
michael@0 304 */
michael@0 305 function promiseTopicObserved(topic)
michael@0 306 {
michael@0 307 let deferred = Promise.defer();
michael@0 308 Services.obs.addObserver(function PTO_observe(subject, topic, data) {
michael@0 309 Services.obs.removeObserver(PTO_observe, topic);
michael@0 310 deferred.resolve([subject, data]);
michael@0 311 }, topic, false);
michael@0 312 return deferred.promise;
michael@0 313 }
michael@0 314
michael@0 315 /**
michael@0 316 * Clears history asynchronously.
michael@0 317 *
michael@0 318 * @return {Promise}
michael@0 319 * @resolves When history has been cleared.
michael@0 320 * @rejects Never.
michael@0 321 */
michael@0 322 function promiseClearHistory() {
michael@0 323 let promise = promiseTopicObserved(PlacesUtils.TOPIC_EXPIRATION_FINISHED);
michael@0 324 PlacesUtils.bhistory.removeAllPages();
michael@0 325 return promise;
michael@0 326 }
michael@0 327
michael@0 328 /**
michael@0 329 * Waits for the next top-level document load in the current browser. The URI
michael@0 330 * of the document is compared against aExpectedURL. The load is then stopped
michael@0 331 * before it actually starts.
michael@0 332 *
michael@0 333 * @param aExpectedURL
michael@0 334 * The URL of the document that is expected to load.
michael@0 335 * @return promise
michael@0 336 */
michael@0 337 function waitForDocLoadAndStopIt(aExpectedURL) {
michael@0 338 let deferred = Promise.defer();
michael@0 339 let progressListener = {
michael@0 340 onStateChange: function (webProgress, req, flags, status) {
michael@0 341 info("waitForDocLoadAndStopIt: onStateChange: " + req.name);
michael@0 342 let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
michael@0 343 Ci.nsIWebProgressListener.STATE_START;
michael@0 344 if ((flags & docStart) && webProgress.isTopLevel) {
michael@0 345 info("waitForDocLoadAndStopIt: Document start: " +
michael@0 346 req.QueryInterface(Ci.nsIChannel).URI.spec);
michael@0 347 is(req.originalURI.spec, aExpectedURL,
michael@0 348 "waitForDocLoadAndStopIt: The expected URL was loaded");
michael@0 349 req.cancel(Components.results.NS_ERROR_FAILURE);
michael@0 350 gBrowser.removeProgressListener(progressListener);
michael@0 351 deferred.resolve();
michael@0 352 }
michael@0 353 },
michael@0 354 };
michael@0 355 gBrowser.addProgressListener(progressListener);
michael@0 356 info("waitForDocLoadAndStopIt: Waiting for URL: " + aExpectedURL);
michael@0 357 return deferred.promise;
michael@0 358 }
michael@0 359
michael@0 360 let FullZoomHelper = {
michael@0 361
michael@0 362 selectTabAndWaitForLocationChange: function selectTabAndWaitForLocationChange(tab) {
michael@0 363 if (!tab)
michael@0 364 throw new Error("tab must be given.");
michael@0 365 if (gBrowser.selectedTab == tab)
michael@0 366 return Promise.resolve();
michael@0 367 gBrowser.selectedTab = tab;
michael@0 368 return this.waitForLocationChange();
michael@0 369 },
michael@0 370
michael@0 371 removeTabAndWaitForLocationChange: function removeTabAndWaitForLocationChange(tab) {
michael@0 372 tab = tab || gBrowser.selectedTab;
michael@0 373 let selected = gBrowser.selectedTab == tab;
michael@0 374 gBrowser.removeTab(tab);
michael@0 375 if (selected)
michael@0 376 return this.waitForLocationChange();
michael@0 377 return Promise.resolve();
michael@0 378 },
michael@0 379
michael@0 380 waitForLocationChange: function waitForLocationChange() {
michael@0 381 let deferred = Promise.defer();
michael@0 382 Services.obs.addObserver(function obs(subj, topic, data) {
michael@0 383 Services.obs.removeObserver(obs, topic);
michael@0 384 deferred.resolve();
michael@0 385 }, "browser-fullZoom:location-change", false);
michael@0 386 return deferred.promise;
michael@0 387 },
michael@0 388
michael@0 389 load: function load(tab, url) {
michael@0 390 let deferred = Promise.defer();
michael@0 391 let didLoad = false;
michael@0 392 let didZoom = false;
michael@0 393
michael@0 394 tab.linkedBrowser.addEventListener("load", function (event) {
michael@0 395 event.currentTarget.removeEventListener("load", arguments.callee, true);
michael@0 396 didLoad = true;
michael@0 397 if (didZoom)
michael@0 398 deferred.resolve();
michael@0 399 }, true);
michael@0 400
michael@0 401 this.waitForLocationChange().then(function () {
michael@0 402 didZoom = true;
michael@0 403 if (didLoad)
michael@0 404 deferred.resolve();
michael@0 405 });
michael@0 406
michael@0 407 tab.linkedBrowser.loadURI(url);
michael@0 408
michael@0 409 return deferred.promise;
michael@0 410 },
michael@0 411
michael@0 412 zoomTest: function zoomTest(tab, val, msg) {
michael@0 413 is(ZoomManager.getZoomForBrowser(tab.linkedBrowser), val, msg);
michael@0 414 },
michael@0 415
michael@0 416 enlarge: function enlarge() {
michael@0 417 let deferred = Promise.defer();
michael@0 418 FullZoom.enlarge(function () deferred.resolve());
michael@0 419 return deferred.promise;
michael@0 420 },
michael@0 421
michael@0 422 reduce: function reduce() {
michael@0 423 let deferred = Promise.defer();
michael@0 424 FullZoom.reduce(function () deferred.resolve());
michael@0 425 return deferred.promise;
michael@0 426 },
michael@0 427
michael@0 428 reset: function reset() {
michael@0 429 let deferred = Promise.defer();
michael@0 430 FullZoom.reset(function () deferred.resolve());
michael@0 431 return deferred.promise;
michael@0 432 },
michael@0 433
michael@0 434 BACK: 0,
michael@0 435 FORWARD: 1,
michael@0 436 navigate: function navigate(direction) {
michael@0 437 let deferred = Promise.defer();
michael@0 438 let didPs = false;
michael@0 439 let didZoom = false;
michael@0 440
michael@0 441 gBrowser.addEventListener("pageshow", function (event) {
michael@0 442 gBrowser.removeEventListener("pageshow", arguments.callee, true);
michael@0 443 didPs = true;
michael@0 444 if (didZoom)
michael@0 445 deferred.resolve();
michael@0 446 }, true);
michael@0 447
michael@0 448 if (direction == this.BACK)
michael@0 449 gBrowser.goBack();
michael@0 450 else if (direction == this.FORWARD)
michael@0 451 gBrowser.goForward();
michael@0 452
michael@0 453 this.waitForLocationChange().then(function () {
michael@0 454 didZoom = true;
michael@0 455 if (didPs)
michael@0 456 deferred.resolve();
michael@0 457 });
michael@0 458 return deferred.promise;
michael@0 459 },
michael@0 460
michael@0 461 failAndContinue: function failAndContinue(func) {
michael@0 462 return function (err) {
michael@0 463 ok(false, err);
michael@0 464 func();
michael@0 465 };
michael@0 466 },
michael@0 467 };

mercurial