Bug 1003461 - Shift + Switch to Tab no longer respected. r=mano
authorMarco Bonardo <mbonardo@mozilla.com>
Wed, 04 Jun 2014 14:23:31 +0200
changeset 205790 035c1df29690b37ecd5baaf8bf24138bbf0fb491
parent 205711 875df781fa8bf83c4f6b056706269ec75daf258a
child 205791 f54eeeffe2a2317e81bbf39e5a844e6a29255d49
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmano
bugs1003461
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1003461 - Shift + Switch to Tab no longer respected. r=mano
browser/base/content/test/general/browser.ini
browser/base/content/test/general/browser_bug1003461-switchtab-override.js
browser/base/content/test/general/head.js
browser/base/content/urlbarBindings.xml
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -420,8 +420,9 @@ skip-if = (os == "win" && !debug) || e10
 [browser_wyciwyg_urlbarCopying.js]
 skip-if = e10s # Bug ?????? - test directly manipulates content (content.document.getElementById)
 [browser_zbug569342.js]
 skip-if = e10s # Bug 516755 - SessionStore disabled for e10s
 [browser_registerProtocolHandler_notification.js]
 skip-if = e10s # Bug 940206 - nsIWebContentHandlerRegistrar::registerProtocolHandler doesn't work in e10s
 [browser_no_mcb_on_http_site.js]
 skip-if = e10s # Bug 516755 - SessionStore disabled for e10s
+[browser_bug1003461-switchtab-override.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_bug1003461-switchtab-override.js
@@ -0,0 +1,63 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+add_task(function* test_switchtab_override() {
+  let testURL = "http://example.org/browser/browser/base/content/test/general/dummy_page.html";
+
+  info("Opening first tab");
+  let tab = gBrowser.addTab(testURL);
+  let deferred = Promise.defer();
+  whenTabLoaded(tab, deferred.resolve);
+  yield deferred.promise;
+
+  info("Opening and selecting second tab");
+  let secondTab = gBrowser.selectedTab = gBrowser.addTab();
+  registerCleanupFunction(() => {
+    try {
+      gBrowser.removeTab(tab);
+      gBrowser.removeTab(secondTab);
+    } catch(ex) { /* tabs may have already been closed in case of failure */ }
+  });
+
+  info("Wait for autocomplete")
+  deferred = Promise.defer();
+  let onSearchComplete = gURLBar.onSearchComplete;
+  registerCleanupFunction(() => {
+    gURLBar.onSearchComplete = onSearchComplete;
+  });
+  gURLBar.onSearchComplete = function () {
+    ok(gURLBar.popupOpen, "The autocomplete popup is correctly open");
+    onSearchComplete.apply(gURLBar);
+    deferred.resolve();
+  }
+  
+  gURLBar.focus();
+  gURLBar.value = "dummy_pag";
+  EventUtils.synthesizeKey("e" , {});
+  yield deferred.promise;
+
+  info("Select first autocomplete popup entry");
+  EventUtils.synthesizeKey("VK_DOWN" , {});
+  ok(/moz-action:switchtab/.test(gURLBar.value), "switch to tab entry found");
+
+  info("Override switch-to-tab");
+  let deferred = Promise.defer();
+  // In case of failure this would switch tab.
+  let onTabSelect = event => {
+    deferred.reject(new Error("Should have overridden switch to tab"));
+  };
+  gBrowser.tabContainer.addEventListener("TabSelect", onTabSelect, false);
+  registerCleanupFunction(() => {
+    gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect, false);
+  });
+  // Otherwise it would load the page.
+  whenTabLoaded(secondTab, deferred.resolve);
+
+  EventUtils.synthesizeKey("VK_SHIFT" , { type: "keydown" });
+  EventUtils.synthesizeKey("VK_RETURN" , { });
+  EventUtils.synthesizeKey("VK_SHIFT" , { type: "keyup" });
+  yield deferred.promise;
+
+  yield promiseClearHistory();
+});
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -288,16 +288,49 @@ function promiseHistoryClearedState(aURI
       callbackDone();
     });
   });
 
   return deferred.promise;
 }
 
 /**
+ * Allows waiting for an observer notification once.
+ *
+ * @param topic
+ *        Notification topic to observe.
+ *
+ * @return {Promise}
+ * @resolves The array [subject, data] from the observed notification.
+ * @rejects Never.
+ */
+function promiseTopicObserved(topic)
+{
+  let deferred = Promise.defer();
+  Services.obs.addObserver(function PTO_observe(subject, topic, data) {
+    Services.obs.removeObserver(PTO_observe, topic);
+    deferred.resolve([subject, data]);
+  }, topic, false);
+  return deferred.promise;
+}
+
+/**
+ * Clears history asynchronously.
+ *
+ * @return {Promise}
+ * @resolves When history has been cleared.
+ * @rejects Never.
+ */
+function promiseClearHistory() {
+  let promise = promiseTopicObserved(PlacesUtils.TOPIC_EXPIRATION_FINISHED);
+  PlacesUtils.bhistory.removeAllPages();
+  return promise;
+}
+
+/**
  * Waits for the next top-level document load in the current browser.  The URI
  * of the document is compared against aExpectedURL.  The load is then stopped
  * before it actually starts.
  *
  * @param aExpectedURL
  *        The URL of the document that is expected to load.
  * @return promise
  */
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -138,17 +138,19 @@
         It should return the value that the setter should use.
       -->
       <method name="onBeforeValueSet">
         <parameter name="aValue"/>
         <body><![CDATA[
           this._value = aValue;
           var returnValue = aValue;
           var action = this._parseActionUrl(aValue);
-          if (action) {
+          // Don't put back the action if we are invoked while override actions
+          // is active.
+          if (action && this._numNoActionsKeys <= 0) {
             returnValue = action.param;
             this.setAttribute("actiontype", action.type);
           } else {
             this.removeAttribute("actiontype");
           }
           return returnValue;
         ]]></body>
       </method>