Bug 1220124 - Add support for chrome.tabs.onhighlight. r=kmag
authorMatthew Wein <mwein@mozilla.com>
Sun, 07 Feb 2016 18:35:22 -0800
changeset 324267 57774ff596857a1567ff5e40ce44cbbe2ec8308a
parent 324266 e3f38a0b663f2c0aeb5bef33cf7e79868d7d4853
child 324268 4245d4c579beb4be51281240b8cef73cdccb0400
push id1128
push userjlund@mozilla.com
push dateWed, 01 Jun 2016 01:31:59 +0000
treeherdermozilla-release@fe0d30de989d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskmag
bugs1220124
milestone47.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 1220124 - Add support for chrome.tabs.onhighlight. r=kmag MozReview-Commit-ID: BB6vJl8qV4l
browser/components/extensions/ext-tabs.js
browser/components/extensions/test/browser/browser.ini
browser/components/extensions/test/browser/browser_ext_tabs_onHighlighted.js
--- a/browser/components/extensions/ext-tabs.js
+++ b/browser/components/extensions/ext-tabs.js
@@ -149,16 +149,29 @@ extensions.registerSchemaAPI("tabs", nul
         WindowListManager.addOpenListener(windowListener);
         AllWindowEvents.addListener("TabOpen", listener);
         return () => {
           WindowListManager.removeOpenListener(windowListener);
           AllWindowEvents.removeListener("TabOpen", listener);
         };
       }).api(),
 
+      /**
+       * Since multiple tabs currently can't be highlighted, onHighlighted
+       * essentially acts an alias for self.tabs.onActivated but returns
+       * the tabId in an array to match the API.
+       * @see  https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/Tabs/onHighlighted
+      */
+      onHighlighted: new WindowEventManager(context, "tabs.onHighlighted", "TabSelect", (fire, event) => {
+        let tab = event.originalTarget;
+        let tabIds = [TabManager.getId(tab)];
+        let windowId = WindowManager.getId(tab.ownerDocument.defaultView);
+        fire({tabIds, windowId});
+      }).api(),
+
       onAttached: new EventManager(context, "tabs.onAttached", fire => {
         let fireForTab = tab => {
           let newWindowId = WindowManager.getId(tab.ownerDocument.defaultView);
           fire(TabManager.getId(tab), {newWindowId, newPosition: tab._tPos});
         };
 
         let listener = event => {
           if (event.detail.adoptedTab) {
--- a/browser/components/extensions/test/browser/browser.ini
+++ b/browser/components/extensions/test/browser/browser.ini
@@ -39,13 +39,14 @@ support-files =
 [browser_ext_tabs_create_invalid_url.js]
 [browser_ext_tabs_duplicate.js]
 [browser_ext_tabs_update.js]
 [browser_ext_tabs_update_url.js]
 [browser_ext_tabs_onUpdated.js]
 [browser_ext_tabs_sendMessage.js]
 [browser_ext_tabs_move.js]
 [browser_ext_tabs_move_window.js]
+[browser_ext_tabs_onHighlighted.js]
 [browser_ext_windows_create_tabId.js]
 [browser_ext_windows_update.js]
 [browser_ext_contentscript_connect.js]
 [browser_ext_tab_runtimeConnect.js]
 [browser_ext_webNavigation_getFrames.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_onHighlighted.js
@@ -0,0 +1,118 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+add_task(function* testTabEvents() {
+  function background() {
+    /** The list of active tab ID's */
+    let tabIds = [];
+
+    /**
+     * Stores the events that fire for each tab.
+     *
+     * events {
+     *   tabId1: [event1, event2, ...],
+     *   tabId2: [event1, event2, ...],
+     * }
+     */
+    let events = {};
+
+    browser.tabs.onActivated.addListener((info) => {
+      if (info.tabId in events) {
+        events[info.tabId].push("onActivated");
+      } else {
+        events[info.tabId] = ["onActivated"];
+      }
+    });
+
+    browser.tabs.onHighlighted.addListener((info) => {
+      if (info.tabIds[0] in events) {
+        events[info.tabIds[0]].push("onHighlighted");
+      } else {
+        events[info.tabIds[0]] = ["onHighlighted"];
+      }
+    });
+
+    /**
+     * Asserts that the expected events are fired for the tab with id = tabId.
+     * The events associated to the specified tab are removed after this check is made.
+     */
+    function expectEvents(tabId, expectedEvents) {
+      browser.test.log(`Expecting events: ${expectedEvents.join(", ")}`);
+
+      return new Promise(resolve => {
+        setTimeout(resolve, 0);
+      }).then(() => {
+        browser.test.assertEq(expectedEvents.length, events[tabId].length,
+         `Got expected number of events for ${tabId}`);
+        for (let [i, name] of expectedEvents.entries()) {
+          browser.test.assertEq(name, i in events[tabId] && events[tabId][i],
+                                `Got expected ${name} event`);
+        }
+        delete events[tabId];
+      });
+    }
+
+    /**
+     * Opens a new tab and asserts that the correct events are fired.
+     */
+    function openTab(windowId) {
+      return browser.tabs.create({windowId}).then(tab => {
+        tabIds.push(tab.id);
+        browser.test.log(`Opened tab ${tab.id}`);
+        return expectEvents(tab.id, [
+          "onActivated",
+          "onHighlighted",
+        ]);
+      });
+    }
+
+    /**
+     * Highlights an existing tab and asserts that the correct events are fired.
+     */
+    function highlightTab(tabId) {
+      browser.test.log(`Highlighting tab ${tabId}`);
+      return browser.tabs.update(tabId, {active: true}).then(tab => {
+        browser.test.assertEq(tab.id, tabId, `Tab ${tab.id} highlighted`);
+        return expectEvents(tab.id, [
+          "onActivated",
+          "onHighlighted",
+        ]);
+      });
+    }
+
+    /**
+     * The main entry point to the tests.
+     */
+    browser.tabs.query({active: true, currentWindow: true}, tabs => {
+      let activeWindow = tabs[0].windowId;
+      Promise.all([
+        openTab(activeWindow),
+        openTab(activeWindow),
+        openTab(activeWindow),
+      ]).then(() => {
+        return Promise.all([
+          highlightTab(tabIds[0]),
+          highlightTab(tabIds[1]),
+          highlightTab(tabIds[2]),
+        ]);
+      }).then(() => {
+        return Promise.all(tabIds.map(id => browser.tabs.remove(id)));
+      }).then(() => {
+        browser.test.notifyPass("tabs.highlight");
+      });
+    });
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "permissions": ["tabs"],
+    },
+
+    background,
+  });
+
+  yield extension.startup();
+  yield extension.awaitFinish("tabs.highlight");
+  yield extension.unload();
+});