From 478824de97c8567e492a4188d4ef099f50bb0952 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Mon, 7 Sep 2015 09:57:46 -0700 Subject: [PATCH] Bug 1202482 - [webext] Implement browser.extension.getViews (r=gabor) --- .../extensions/test/browser/browser.ini | 1 + .../test/browser/browser_ext_getViews.js | 186 ++++++++++++++++++ .../components/extensions/ext-extension.js | 22 +++ 3 files changed, 209 insertions(+) create mode 100644 browser/components/extensions/test/browser/browser_ext_getViews.js diff --git a/browser/components/extensions/test/browser/browser.ini b/browser/components/extensions/test/browser/browser.ini index 968e86cd87d7..dcbd5900495e 100644 --- a/browser/components/extensions/test/browser/browser.ini +++ b/browser/components/extensions/test/browser/browser.ini @@ -4,6 +4,7 @@ skip-if = os == 'android' || buildapp == 'b2g' || os == 'mac' [browser_ext_simple.js] [browser_ext_currentWindow.js] [browser_ext_browserAction_simple.js] +[browser_ext_getViews.js] [browser_ext_tabs_executeScript.js] [browser_ext_tabs_query.js] [browser_ext_tabs_update.js] diff --git a/browser/components/extensions/test/browser/browser_ext_getViews.js b/browser/components/extensions/test/browser/browser_ext_getViews.js new file mode 100644 index 000000000000..8ba6c32052ac --- /dev/null +++ b/browser/components/extensions/test/browser/browser_ext_getViews.js @@ -0,0 +1,186 @@ +let {CustomizableUI} = Cu.import("resource:///modules/CustomizableUI.jsm", {}); + +function makeWidgetId(id) +{ + id = id.toLowerCase(); + return id.replace(/[^a-z0-9_-]/g, "_"); +} + +function genericChecker() +{ + var kind = "background"; + var path = window.location.pathname; + if (path.indexOf("popup") != -1) { + kind = "popup"; + } else if (path.indexOf("tab") != -1) { + kind = "tab"; + } + window.kind = kind; + + browser.test.onMessage.addListener((msg, ...args) => { + if (msg == kind + "-check-views") { + var views = browser.extension.getViews(); + var counts = { + "background": 0, + "tab": 0, + "popup": 0 + }; + for (var i = 0; i < views.length; i++) { + var view = views[i]; + browser.test.assertTrue(view.kind in counts, "view type is valid"); + counts[view.kind]++; + if (view.kind == "background") { + browser.test.assertTrue(view === browser.extension.getBackgroundPage(), + "background page is correct"); + } + } + browser.test.sendMessage("counts", counts); + } else if (msg == kind + "-open-tab") { + browser.tabs.create({windowId: args[0], url: chrome.runtime.getURL("tab.html")}); + } else if (msg == kind + "-close-tab") { + browser.tabs.query({ + windowId: args[0], + }, tabs => { + var tab = tabs.find(tab => tab.url.indexOf("tab.html") != -1); + browser.tabs.remove(tab.id, () => { + browser.test.sendMessage("closed"); + }); + }); + } + }); + browser.test.sendMessage(kind + "-ready"); +} + +add_task(function* () { + let win1 = yield BrowserTestUtils.openNewBrowserWindow(); + let win2 = yield BrowserTestUtils.openNewBrowserWindow(); + + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + "permissions": ["tabs"], + + "browser_action": { + "default_popup": "popup.html" + }, + }, + + files: { + "tab.html": ` + + + + + `, + + "tab.js": genericChecker, + + "popup.html": ` + + + + + `, + + "popup.js": genericChecker, + }, + + background: genericChecker, + }); + + yield Promise.all([extension.startup(), extension.awaitMessage("background-ready")]); + + info("started"); + + let {TabManager, WindowManager} = Cu.import("resource://gre/modules/Extension.jsm", {}); + + let winId1 = WindowManager.getId(win1); + let winId2 = WindowManager.getId(win2); + + function* openTab(winId) { + extension.sendMessage("background-open-tab", winId); + yield extension.awaitMessage("tab-ready"); + } + + function* checkViews(kind, tabCount, popupCount) { + extension.sendMessage(kind + "-check-views"); + let counts = yield extension.awaitMessage("counts"); + is(counts.background, 1, "background count correct"); + is(counts.tab, tabCount, "tab count correct"); + is(counts.popup, popupCount, "popup count correct"); + } + + yield checkViews("background", 0, 0); + + yield openTab(winId1); + + yield checkViews("background", 1, 0); + yield checkViews("tab", 1, 0); + + yield openTab(winId2); + + yield checkViews("background", 2, 0); + + function* triggerPopup(win, callback) { + let widgetId = makeWidgetId(extension.id) + "-browser-action"; + let node = CustomizableUI.getWidget(widgetId).forWindow(win).node; + + let evt = new CustomEvent("command", { + bubbles: true, + cancelable: true + }); + node.dispatchEvent(evt); + + yield extension.awaitMessage("popup-ready"); + + yield callback(); + + let panel = node.querySelector("panel"); + if (panel) { + panel.hidePopup(); + } + } + + yield triggerPopup(win1, function*() { + yield checkViews("background", 2, 1); + yield checkViews("popup", 2, 1); + }); + + yield triggerPopup(win2, function*() { + yield checkViews("background", 2, 1); + yield checkViews("popup", 2, 1); + }); + + info("checking counts after popups"); + + yield checkViews("background", 2, 0); + + info("closing one tab"); + + extension.sendMessage("background-close-tab", winId1); + yield extension.awaitMessage("closed"); + + info("one tab closed, one remains"); + + yield checkViews("background", 1, 0); + + info("opening win1 popup"); + + yield triggerPopup(win1, function*() { + yield checkViews("background", 1, 1); + yield checkViews("tab", 1, 1); + yield checkViews("popup", 1, 1); + }); + + info("opening win2 popup"); + + yield triggerPopup(win2, function*() { + yield checkViews("background", 1, 1); + yield checkViews("tab", 1, 1); + yield checkViews("popup", 1, 1); + }); + + yield extension.unload(); + + yield BrowserTestUtils.closeWindow(win1); + yield BrowserTestUtils.closeWindow(win2); +}); diff --git a/toolkit/components/extensions/ext-extension.js b/toolkit/components/extensions/ext-extension.js index deaebebc4fed..a4d38d043d27 100644 --- a/toolkit/components/extensions/ext-extension.js +++ b/toolkit/components/extensions/ext-extension.js @@ -4,6 +4,28 @@ extensions.registerAPI((extension, context) => { getURL: function(url) { return extension.baseURI.resolve(url); }, + + getViews: function(fetchProperties) { + let result = Cu.cloneInto([], context.cloneScope); + + for (let view of extension.views) { + if (fetchProperties && "type" in fetchProperties) { + if (view.type != fetchProperties.type) { + continue; + } + } + + if (fetchProperties && "windowId" in fetchProperties) { + if (view.windowId != fetchProperties.windowId) { + continue; + } + } + + result.push(view.contentWindow); + } + + return result; + }, }, }; });