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 186432 035c1df29690b37ecd5baaf8bf24138bbf0fb491
parent 186431 875df781fa8bf83c4f6b056706269ec75daf258a
child 186517 f54eeeffe2a2317e81bbf39e5a844e6a29255d49
push id7121
push usermak77@bonardo.net
push dateWed, 04 Jun 2014 12:23:52 +0000
treeherderfx-team@035c1df29690 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmano
bugs1003461
milestone32.0a1
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>