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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/base/content/test/general/head.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,467 @@
     1.4 +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
     1.5 +
     1.6 +XPCOMUtils.defineLazyModuleGetter(this, "Promise",
     1.7 +  "resource://gre/modules/Promise.jsm");
     1.8 +XPCOMUtils.defineLazyModuleGetter(this, "Task",
     1.9 +  "resource://gre/modules/Task.jsm");
    1.10 +XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
    1.11 +  "resource://gre/modules/PlacesUtils.jsm");
    1.12 +
    1.13 +function whenDelayedStartupFinished(aWindow, aCallback) {
    1.14 +  Services.obs.addObserver(function observer(aSubject, aTopic) {
    1.15 +    if (aWindow == aSubject) {
    1.16 +      Services.obs.removeObserver(observer, aTopic);
    1.17 +      executeSoon(aCallback);
    1.18 +    }
    1.19 +  }, "browser-delayed-startup-finished", false);
    1.20 +}
    1.21 +
    1.22 +function findChromeWindowByURI(aURI) {
    1.23 +  let windows = Services.wm.getEnumerator(null);
    1.24 +  while (windows.hasMoreElements()) {
    1.25 +    let win = windows.getNext();
    1.26 +    if (win.location.href == aURI)
    1.27 +      return win;
    1.28 +  }
    1.29 +  return null;
    1.30 +}
    1.31 +
    1.32 +function updateTabContextMenu(tab) {
    1.33 +  let menu = document.getElementById("tabContextMenu");
    1.34 +  if (!tab)
    1.35 +    tab = gBrowser.selectedTab;
    1.36 +  var evt = new Event("");
    1.37 +  tab.dispatchEvent(evt);
    1.38 +  menu.openPopup(tab, "end_after", 0, 0, true, false, evt);
    1.39 +  is(TabContextMenu.contextTab, tab, "TabContextMenu context is the expected tab");
    1.40 +  menu.hidePopup();
    1.41 +}
    1.42 +
    1.43 +function openToolbarCustomizationUI(aCallback, aBrowserWin) {
    1.44 +  if (!aBrowserWin)
    1.45 +    aBrowserWin = window;
    1.46 +
    1.47 +  aBrowserWin.gCustomizeMode.enter();
    1.48 +
    1.49 +  aBrowserWin.gNavToolbox.addEventListener("customizationready", function UI_loaded() {
    1.50 +    aBrowserWin.gNavToolbox.removeEventListener("customizationready", UI_loaded);
    1.51 +    executeSoon(function() {
    1.52 +      aCallback(aBrowserWin)
    1.53 +    });
    1.54 +  });
    1.55 +}
    1.56 +
    1.57 +function closeToolbarCustomizationUI(aCallback, aBrowserWin) {
    1.58 +  aBrowserWin.gNavToolbox.addEventListener("aftercustomization", function unloaded() {
    1.59 +    aBrowserWin.gNavToolbox.removeEventListener("aftercustomization", unloaded);
    1.60 +    executeSoon(aCallback);
    1.61 +  });
    1.62 +
    1.63 +  aBrowserWin.gCustomizeMode.exit();
    1.64 +}
    1.65 +
    1.66 +function waitForCondition(condition, nextTest, errorMsg) {
    1.67 +  var tries = 0;
    1.68 +  var interval = setInterval(function() {
    1.69 +    if (tries >= 30) {
    1.70 +      ok(false, errorMsg);
    1.71 +      moveOn();
    1.72 +    }
    1.73 +    var conditionPassed;
    1.74 +    try {
    1.75 +      conditionPassed = condition();
    1.76 +    } catch (e) {
    1.77 +      ok(false, e + "\n" + e.stack);
    1.78 +      conditionPassed = false;
    1.79 +    }
    1.80 +    if (conditionPassed) {
    1.81 +      moveOn();
    1.82 +    }
    1.83 +    tries++;
    1.84 +  }, 100);
    1.85 +  var moveOn = function() { clearInterval(interval); nextTest(); };
    1.86 +}
    1.87 +
    1.88 +function getTestPlugin(aName) {
    1.89 +  var pluginName = aName || "Test Plug-in";
    1.90 +  var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
    1.91 +  var tags = ph.getPluginTags();
    1.92 +
    1.93 +  // Find the test plugin
    1.94 +  for (var i = 0; i < tags.length; i++) {
    1.95 +    if (tags[i].name == pluginName)
    1.96 +      return tags[i];
    1.97 +  }
    1.98 +  ok(false, "Unable to find plugin");
    1.99 +  return null;
   1.100 +}
   1.101 +
   1.102 +// call this to set the test plugin(s) initially expected enabled state.
   1.103 +// it will automatically be reset to it's previous value after the test
   1.104 +// ends
   1.105 +function setTestPluginEnabledState(newEnabledState, pluginName) {
   1.106 +  var plugin = getTestPlugin(pluginName);
   1.107 +  var oldEnabledState = plugin.enabledState;
   1.108 +  plugin.enabledState = newEnabledState;
   1.109 +  SimpleTest.registerCleanupFunction(function() {
   1.110 +    getTestPlugin(pluginName).enabledState = oldEnabledState;
   1.111 +  });
   1.112 +}
   1.113 +
   1.114 +// after a test is done using the plugin doorhanger, we should just clear
   1.115 +// any permissions that may have crept in
   1.116 +function clearAllPluginPermissions() {
   1.117 +  let perms = Services.perms.enumerator;
   1.118 +  while (perms.hasMoreElements()) {
   1.119 +    let perm = perms.getNext();
   1.120 +    if (perm.type.startsWith('plugin')) {
   1.121 +      Services.perms.remove(perm.host, perm.type);
   1.122 +    }
   1.123 +  }
   1.124 +}
   1.125 +
   1.126 +function updateBlocklist(aCallback) {
   1.127 +  var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
   1.128 +                          .getService(Ci.nsITimerCallback);
   1.129 +  var observer = function() {
   1.130 +    Services.obs.removeObserver(observer, "blocklist-updated");
   1.131 +    SimpleTest.executeSoon(aCallback);
   1.132 +  };
   1.133 +  Services.obs.addObserver(observer, "blocklist-updated", false);
   1.134 +  blocklistNotifier.notify(null);
   1.135 +}
   1.136 +
   1.137 +var _originalTestBlocklistURL = null;
   1.138 +function setAndUpdateBlocklist(aURL, aCallback) {
   1.139 +  if (!_originalTestBlocklistURL)
   1.140 +    _originalTestBlocklistURL = Services.prefs.getCharPref("extensions.blocklist.url");
   1.141 +  Services.prefs.setCharPref("extensions.blocklist.url", aURL);
   1.142 +  updateBlocklist(aCallback);
   1.143 +}
   1.144 +
   1.145 +function resetBlocklist() {
   1.146 +  Services.prefs.setCharPref("extensions.blocklist.url", _originalTestBlocklistURL);
   1.147 +}
   1.148 +
   1.149 +function whenNewWindowLoaded(aOptions, aCallback) {
   1.150 +  let win = OpenBrowserWindow(aOptions);
   1.151 +  win.addEventListener("load", function onLoad() {
   1.152 +    win.removeEventListener("load", onLoad, false);
   1.153 +    aCallback(win);
   1.154 +  }, false);
   1.155 +}
   1.156 +
   1.157 +/**
   1.158 + * Waits for all pending async statements on the default connection, before
   1.159 + * proceeding with aCallback.
   1.160 + *
   1.161 + * @param aCallback
   1.162 + *        Function to be called when done.
   1.163 + * @param aScope
   1.164 + *        Scope for the callback.
   1.165 + * @param aArguments
   1.166 + *        Arguments array for the callback.
   1.167 + *
   1.168 + * @note The result is achieved by asynchronously executing a query requiring
   1.169 + *       a write lock.  Since all statements on the same connection are
   1.170 + *       serialized, the end of this write operation means that all writes are
   1.171 + *       complete.  Note that WAL makes so that writers don't block readers, but
   1.172 + *       this is a problem only across different connections.
   1.173 + */
   1.174 +function waitForAsyncUpdates(aCallback, aScope, aArguments) {
   1.175 +  let scope = aScope || this;
   1.176 +  let args = aArguments || [];
   1.177 +  let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
   1.178 +                              .DBConnection;
   1.179 +  let begin = db.createAsyncStatement("BEGIN EXCLUSIVE");
   1.180 +  begin.executeAsync();
   1.181 +  begin.finalize();
   1.182 +
   1.183 +  let commit = db.createAsyncStatement("COMMIT");
   1.184 +  commit.executeAsync({
   1.185 +    handleResult: function() {},
   1.186 +    handleError: function() {},
   1.187 +    handleCompletion: function(aReason) {
   1.188 +      aCallback.apply(scope, args);
   1.189 +    }
   1.190 +  });
   1.191 +  commit.finalize();
   1.192 +}
   1.193 +
   1.194 +/**
   1.195 + * Asynchronously check a url is visited.
   1.196 +
   1.197 + * @param aURI The URI.
   1.198 + * @param aExpectedValue The expected value.
   1.199 + * @return {Promise}
   1.200 + * @resolves When the check has been added successfully.
   1.201 + * @rejects JavaScript exception.
   1.202 + */
   1.203 +function promiseIsURIVisited(aURI, aExpectedValue) {
   1.204 +  let deferred = Promise.defer();
   1.205 +  PlacesUtils.asyncHistory.isURIVisited(aURI, function(aURI, aIsVisited) {
   1.206 +    deferred.resolve(aIsVisited);
   1.207 +  });
   1.208 +
   1.209 +  return deferred.promise;
   1.210 +}
   1.211 +
   1.212 +function whenNewTabLoaded(aWindow, aCallback) {
   1.213 +  aWindow.BrowserOpenTab();
   1.214 +
   1.215 +  let browser = aWindow.gBrowser.selectedBrowser;
   1.216 +  if (browser.contentDocument.readyState === "complete") {
   1.217 +    aCallback();
   1.218 +    return;
   1.219 +  }
   1.220 +
   1.221 +  whenTabLoaded(aWindow.gBrowser.selectedTab, aCallback);
   1.222 +}
   1.223 +
   1.224 +function whenTabLoaded(aTab, aCallback) {
   1.225 +  let browser = aTab.linkedBrowser;
   1.226 +  browser.addEventListener("load", function onLoad() {
   1.227 +    browser.removeEventListener("load", onLoad, true);
   1.228 +    executeSoon(aCallback);
   1.229 +  }, true);
   1.230 +}
   1.231 +
   1.232 +function addVisits(aPlaceInfo, aCallback) {
   1.233 +  let places = [];
   1.234 +  if (aPlaceInfo instanceof Ci.nsIURI) {
   1.235 +    places.push({ uri: aPlaceInfo });
   1.236 +  } else if (Array.isArray(aPlaceInfo)) {
   1.237 +    places = places.concat(aPlaceInfo);
   1.238 +  } else {
   1.239 +    places.push(aPlaceInfo);
   1.240 +   }
   1.241 +
   1.242 +  // Create mozIVisitInfo for each entry.
   1.243 +  let now = Date.now();
   1.244 +  for (let i = 0; i < places.length; i++) {
   1.245 +    if (!places[i].title) {
   1.246 +      places[i].title = "test visit for " + places[i].uri.spec;
   1.247 +    }
   1.248 +    places[i].visits = [{
   1.249 +      transitionType: places[i].transition === undefined ? Ci.nsINavHistoryService.TRANSITION_LINK
   1.250 +                                                         : places[i].transition,
   1.251 +      visitDate: places[i].visitDate || (now++) * 1000,
   1.252 +      referrerURI: places[i].referrer
   1.253 +    }];
   1.254 +  }
   1.255 +
   1.256 +  PlacesUtils.asyncHistory.updatePlaces(
   1.257 +    places,
   1.258 +    {
   1.259 +      handleError: function AAV_handleError() {
   1.260 +        throw("Unexpected error in adding visit.");
   1.261 +      },
   1.262 +      handleResult: function () {},
   1.263 +      handleCompletion: function UP_handleCompletion() {
   1.264 +        if (aCallback)
   1.265 +          aCallback();
   1.266 +      }
   1.267 +    }
   1.268 +  );
   1.269 +}
   1.270 +
   1.271 +/**
   1.272 + * Ensures that the specified URIs are either cleared or not.
   1.273 + *
   1.274 + * @param aURIs
   1.275 + *        Array of page URIs
   1.276 + * @param aShouldBeCleared
   1.277 + *        True if each visit to the URI should be cleared, false otherwise
   1.278 + */
   1.279 +function promiseHistoryClearedState(aURIs, aShouldBeCleared) {
   1.280 +  let deferred = Promise.defer();
   1.281 +  let callbackCount = 0;
   1.282 +  let niceStr = aShouldBeCleared ? "no longer" : "still";
   1.283 +  function callbackDone() {
   1.284 +    if (++callbackCount == aURIs.length)
   1.285 +      deferred.resolve();
   1.286 +  }
   1.287 +  aURIs.forEach(function (aURI) {
   1.288 +    PlacesUtils.asyncHistory.isURIVisited(aURI, function(aURI, aIsVisited) {
   1.289 +      is(aIsVisited, !aShouldBeCleared,
   1.290 +         "history visit " + aURI.spec + " should " + niceStr + " exist");
   1.291 +      callbackDone();
   1.292 +    });
   1.293 +  });
   1.294 +
   1.295 +  return deferred.promise;
   1.296 +}
   1.297 +
   1.298 +/**
   1.299 + * Allows waiting for an observer notification once.
   1.300 + *
   1.301 + * @param topic
   1.302 + *        Notification topic to observe.
   1.303 + *
   1.304 + * @return {Promise}
   1.305 + * @resolves The array [subject, data] from the observed notification.
   1.306 + * @rejects Never.
   1.307 + */
   1.308 +function promiseTopicObserved(topic)
   1.309 +{
   1.310 +  let deferred = Promise.defer();
   1.311 +  Services.obs.addObserver(function PTO_observe(subject, topic, data) {
   1.312 +    Services.obs.removeObserver(PTO_observe, topic);
   1.313 +    deferred.resolve([subject, data]);
   1.314 +  }, topic, false);
   1.315 +  return deferred.promise;
   1.316 +}
   1.317 +
   1.318 +/**
   1.319 + * Clears history asynchronously.
   1.320 + *
   1.321 + * @return {Promise}
   1.322 + * @resolves When history has been cleared.
   1.323 + * @rejects Never.
   1.324 + */
   1.325 +function promiseClearHistory() {
   1.326 +  let promise = promiseTopicObserved(PlacesUtils.TOPIC_EXPIRATION_FINISHED);
   1.327 +  PlacesUtils.bhistory.removeAllPages();
   1.328 +  return promise;
   1.329 +}
   1.330 +
   1.331 +/**
   1.332 + * Waits for the next top-level document load in the current browser.  The URI
   1.333 + * of the document is compared against aExpectedURL.  The load is then stopped
   1.334 + * before it actually starts.
   1.335 + *
   1.336 + * @param aExpectedURL
   1.337 + *        The URL of the document that is expected to load.
   1.338 + * @return promise
   1.339 + */
   1.340 +function waitForDocLoadAndStopIt(aExpectedURL) {
   1.341 +  let deferred = Promise.defer();
   1.342 +  let progressListener = {
   1.343 +    onStateChange: function (webProgress, req, flags, status) {
   1.344 +      info("waitForDocLoadAndStopIt: onStateChange: " + req.name);
   1.345 +      let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
   1.346 +                     Ci.nsIWebProgressListener.STATE_START;
   1.347 +      if ((flags & docStart) && webProgress.isTopLevel) {
   1.348 +        info("waitForDocLoadAndStopIt: Document start: " +
   1.349 +             req.QueryInterface(Ci.nsIChannel).URI.spec);
   1.350 +        is(req.originalURI.spec, aExpectedURL,
   1.351 +           "waitForDocLoadAndStopIt: The expected URL was loaded");
   1.352 +        req.cancel(Components.results.NS_ERROR_FAILURE);
   1.353 +        gBrowser.removeProgressListener(progressListener);
   1.354 +        deferred.resolve();
   1.355 +      }
   1.356 +    },
   1.357 +  };
   1.358 +  gBrowser.addProgressListener(progressListener);
   1.359 +  info("waitForDocLoadAndStopIt: Waiting for URL: " + aExpectedURL);
   1.360 +  return deferred.promise;
   1.361 +}
   1.362 +
   1.363 +let FullZoomHelper = {
   1.364 +
   1.365 +  selectTabAndWaitForLocationChange: function selectTabAndWaitForLocationChange(tab) {
   1.366 +    if (!tab)
   1.367 +      throw new Error("tab must be given.");
   1.368 +    if (gBrowser.selectedTab == tab)
   1.369 +      return Promise.resolve();
   1.370 +    gBrowser.selectedTab = tab;
   1.371 +    return this.waitForLocationChange();
   1.372 +  },
   1.373 +
   1.374 +  removeTabAndWaitForLocationChange: function removeTabAndWaitForLocationChange(tab) {
   1.375 +    tab = tab || gBrowser.selectedTab;
   1.376 +    let selected = gBrowser.selectedTab == tab;
   1.377 +    gBrowser.removeTab(tab);
   1.378 +    if (selected)
   1.379 +      return this.waitForLocationChange();
   1.380 +    return Promise.resolve();
   1.381 +  },
   1.382 +
   1.383 +  waitForLocationChange: function waitForLocationChange() {
   1.384 +    let deferred = Promise.defer();
   1.385 +    Services.obs.addObserver(function obs(subj, topic, data) {
   1.386 +      Services.obs.removeObserver(obs, topic);
   1.387 +      deferred.resolve();
   1.388 +    }, "browser-fullZoom:location-change", false);
   1.389 +    return deferred.promise;
   1.390 +  },
   1.391 +
   1.392 +  load: function load(tab, url) {
   1.393 +    let deferred = Promise.defer();
   1.394 +    let didLoad = false;
   1.395 +    let didZoom = false;
   1.396 +
   1.397 +    tab.linkedBrowser.addEventListener("load", function (event) {
   1.398 +      event.currentTarget.removeEventListener("load", arguments.callee, true);
   1.399 +      didLoad = true;
   1.400 +      if (didZoom)
   1.401 +        deferred.resolve();
   1.402 +    }, true);
   1.403 +
   1.404 +    this.waitForLocationChange().then(function () {
   1.405 +      didZoom = true;
   1.406 +      if (didLoad)
   1.407 +        deferred.resolve();
   1.408 +    });
   1.409 +
   1.410 +    tab.linkedBrowser.loadURI(url);
   1.411 +
   1.412 +    return deferred.promise;
   1.413 +  },
   1.414 +
   1.415 +  zoomTest: function zoomTest(tab, val, msg) {
   1.416 +    is(ZoomManager.getZoomForBrowser(tab.linkedBrowser), val, msg);
   1.417 +  },
   1.418 +
   1.419 +  enlarge: function enlarge() {
   1.420 +    let deferred = Promise.defer();
   1.421 +    FullZoom.enlarge(function () deferred.resolve());
   1.422 +    return deferred.promise;
   1.423 +  },
   1.424 +
   1.425 +  reduce: function reduce() {
   1.426 +    let deferred = Promise.defer();
   1.427 +    FullZoom.reduce(function () deferred.resolve());
   1.428 +    return deferred.promise;
   1.429 +  },
   1.430 +
   1.431 +  reset: function reset() {
   1.432 +    let deferred = Promise.defer();
   1.433 +    FullZoom.reset(function () deferred.resolve());
   1.434 +    return deferred.promise;
   1.435 +  },
   1.436 +
   1.437 +  BACK: 0,
   1.438 +  FORWARD: 1,
   1.439 +  navigate: function navigate(direction) {
   1.440 +    let deferred = Promise.defer();
   1.441 +    let didPs = false;
   1.442 +    let didZoom = false;
   1.443 +
   1.444 +    gBrowser.addEventListener("pageshow", function (event) {
   1.445 +      gBrowser.removeEventListener("pageshow", arguments.callee, true);
   1.446 +      didPs = true;
   1.447 +      if (didZoom)
   1.448 +        deferred.resolve();
   1.449 +    }, true);
   1.450 +
   1.451 +    if (direction == this.BACK)
   1.452 +      gBrowser.goBack();
   1.453 +    else if (direction == this.FORWARD)
   1.454 +      gBrowser.goForward();
   1.455 +
   1.456 +    this.waitForLocationChange().then(function () {
   1.457 +      didZoom = true;
   1.458 +      if (didPs)
   1.459 +        deferred.resolve();
   1.460 +    });
   1.461 +    return deferred.promise;
   1.462 +  },
   1.463 +
   1.464 +  failAndContinue: function failAndContinue(func) {
   1.465 +    return function (err) {
   1.466 +      ok(false, err);
   1.467 +      func();
   1.468 +    };
   1.469 +  },
   1.470 +};

mercurial