Bug 1331742 - Part 5 - Add unit tests for browserAction.onClicked r?mixedpuppy
MozReview-Commit-ID: DE7me6moxG
--- a/mobile/android/components/extensions/test/mochitest/chrome.ini
+++ b/mobile/android/components/extensions/test/mochitest/chrome.ini
@@ -1,8 +1,9 @@
[DEFAULT]
support-files =
head.js
../../../../../../toolkit/components/extensions/test/mochitest/chrome_cleanup_script.js
tags = webextensions
+[test_ext_browserAction_onClicked.html]
[test_ext_pageAction.html]
[test_ext_pageAction_popup.html]
--- a/mobile/android/components/extensions/test/mochitest/head.js
+++ b/mobile/android/components/extensions/test/mochitest/head.js
@@ -1,14 +1,13 @@
"use strict";
-/* exported isPageActionShown clickPageAction, AppConstants */
+/* exported AppConstants */
var {AppConstants} = SpecialPowers.Cu.import("resource://gre/modules/AppConstants.jsm", {});
-var {PageActions} = SpecialPowers.Cu.import("resource://gre/modules/PageActions.jsm", {});
{
let chromeScript = SpecialPowers.loadChromeScript(
SimpleTest.getTestFileURL("chrome_cleanup_script.js"));
SimpleTest.registerCleanupFunction(async () => {
await new Promise(resolve => setTimeout(resolve, 0));
@@ -17,16 +16,8 @@ var {PageActions} = SpecialPowers.Cu.imp
let results = await chromeScript.promiseOneMessage("cleanup-results");
chromeScript.destroy();
if (results.extraWindows.length || results.extraTabs.length) {
ok(false, `Test left extra windows or tabs: ${JSON.stringify(results)}\n`);
}
});
}
-
-function isPageActionShown(uuid) {
- return PageActions.isShown(uuid);
-}
-
-function clickPageAction(uuid) {
- PageActions.synthesizeClick(uuid);
-}
new file mode 100644
--- /dev/null
+++ b/mobile/android/components/extensions/test/mochitest/test_ext_browserAction_onClicked.html
@@ -0,0 +1,94 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>BrowserAction Test</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
+ <script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
+ <script type="text/javascript" src="head.js"></script>
+ <link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="text/javascript">
+"use strict";
+
+var {BrowserActions} = SpecialPowers.Cu.import("resource://gre/modules/BrowserActions.jsm", {});
+
+async function background() {
+ browser.test.assertTrue("browserAction" in browser, "Namespace 'browserAction' exists in browser");
+ browser.test.assertTrue("onClicked" in browser.browserAction, "API method 'onClicked' exists in browser.browserAction");
+
+ const tabs = await browser.tabs.query({active: true, currentWindow: true});
+
+ browser.browserAction.onClicked.addListener(tab => {
+ browser.test.sendMessage("browser-action-clicked", tab);
+ });
+
+ browser.test.sendMessage("ready", tabs[0]);
+}
+
+function createExtension(name) {
+ return ExtensionTestUtils.loadExtension({
+ background,
+ manifest: {
+ "name": name,
+ "browser_action": {
+ "default_title": "Browser Action",
+ },
+ },
+ });
+}
+
+function* checkBrowserAction(extension, id, tab) {
+ ok(BrowserActions.isShown(id), "The BrowerAction should be shown");
+ BrowserActions.synthesizeClick(id);
+ const clickedTab = yield extension.awaitMessage("browser-action-clicked");
+ is(clickedTab.id, tab.id, "Got the expected tab id in the browserAction.onClicked event");
+}
+
+add_task(function* test_browserAction() {
+ const extension = createExtension("BrowserAction Extension");
+ yield extension.startup();
+ const tab = yield extension.awaitMessage("ready");
+ let id = `{${extension.uuid}}`;
+ yield checkBrowserAction(extension, id, tab);
+ yield extension.unload();
+
+ ok(!BrowserActions.isShown(id), "The BrowserAction should be removed after the extension unloads");
+});
+
+add_task(function* test_multiple_browserActions() {
+ const ext1 = createExtension("BrowserAction Extension 1");
+ const ext2 = createExtension("BrowserAction Extension 2");
+
+ // Start the first extension and test its browser action.
+ yield ext1.startup();
+ const tab1 = yield ext1.awaitMessage("ready");
+ let id1 = `{${ext1.uuid}}`;
+ yield checkBrowserAction(ext1, id1, tab1);
+
+ // Start the second extension and test its browser action.
+ yield ext2.startup();
+ const tab2 = yield ext2.awaitMessage("ready");
+ let id2 = `{${ext2.uuid}}`;
+ yield checkBrowserAction(ext2, id2, tab2);
+
+ // Verify that the first browser action is still active.
+ yield checkBrowserAction(ext1, id1, tab1);
+
+ // Unload the first extension and verify that the browser action is removed.
+ yield ext1.unload();
+ ok(!BrowserActions.isShown(id1), "The first BrowserAction should be removed after ext1 unloads");
+
+ // Verify that the second browser action is still active.
+ yield checkBrowserAction(ext2, id2, tab2);
+
+ // Unload the second extension and verify that the browser action is removed.
+ yield ext2.unload();
+ ok(!BrowserActions.isShown(id2), "The second BrowserAction should be removed after ext2 unloads");
+});
+</script>
+
+</body>
+</html>
--- a/mobile/android/components/extensions/test/mochitest/test_ext_pageAction.html
+++ b/mobile/android/components/extensions/test/mochitest/test_ext_pageAction.html
@@ -8,16 +8,18 @@
<script type="text/javascript" src="head.js"></script>
<link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="text/javascript">
"use strict";
+var {PageActions} = SpecialPowers.Cu.import("resource://gre/modules/PageActions.jsm", {});
+
let dataURI = "iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAC4klEQVRYhdWXLWzbQBSADQtDAwsHC1tUhUxqfL67lk2tdn+OJg0ODU0rLByqgqINBY6tmlbn7LMTJ5FaFVVBk1G0oUGjG2jT2Y7jxmmcbU/6iJ+f36fz+e5sGP9riCGm9hB37RG+scd4Yo/wsDXCZyIE2xuXsce4bY+wXkAsQtzYmExrfFgvkJkRbkzo1ehoxx5iXcgI/9iYUGt8WH9MqDXEcmNChmEYrRCf2SHWeYgQx3x0tLNRIeKQLTtEFyJEep4NTuhk8BC+yMrwEE3+iozo42d8gK7FAOkMsRiiN8QhW2ttSK5QTfRRV4QoymVeJMvPvDp7gCZigD613MN6yRFA3SWarow9QB9LCfG+NeF9qCtjAKOSQjCqVKhfVsiHEQ+grgx/lRGqUihAc1uL8EFD+KCRO+GrF4J61phcoRoPoEzkYhZYpykh5sMb7kOdIeY+jHKur4QI4Feh4AFX1nVeLxrAvQchGsBz5ls6wa2QdwcvIcE2863bTH79KOvsz/uUYJsp+J0pSzNlDckVqqVGUAF+n6uS7txcOl6wot4JVy70ufDLy4pWLUQVPE81pRI0mGe9oxLMHSeohHvMs/STUNaUK6vDPCvOyxMFDx4achehRDJmHnydnkPww5OFfLxrGIZBFDyYl4LpMzlTQFIP6AQx86w2UeYBccFpJrcKv5L9eGDtUAU6RIELqsB74uynjy/UBRF1gS5BTFxwQT1wTiXoUg9MH7m/3NZRRoi5IJytUbMgzv4Wc832+oQkiKgEehmyMkkpKsFkQV11QsRJL5rJYBLItQgRaUZEmnoZXsomz3vGiWw+I9KMF9SVFOqZEemZekli1jN3U/UOqhHHvC6oWWGElhfSpGdOk6+O9prdwvtLj5BjRsQxdRnot+Zeifpy/2/0stktKTRNLmbk0mwXyl8253fyojj+8rxOHNAhjjm5n0/5OOCGOKBzkrMO0Z75lvSAzKlrF32Z/3z8BqLAn+yMV7VhAAAAAElFTkSuQmCC";
let image = atob(dataURI);
const IMAGE_ARRAYBUFFER = Uint8Array.from(image, byte => byte.charCodeAt(0)).buffer;
async function background() {
browser.test.assertTrue("pageAction" in browser, "Namespace 'pageAction' exists in browser");
browser.test.assertTrue("show" in browser.pageAction, "API method 'show' exists in browser.pageAction");
@@ -35,23 +37,17 @@ async function background() {
});
}
});
browser.pageAction.onClicked.addListener(tab => {
browser.test.sendMessage("page-action-clicked", tab);
});
- const extensionInfo = {
- // Extract the assigned uuid from the background page url.
- uuid: `{${window.location.hostname}}`,
- tab: tabs[0],
- };
-
- browser.test.sendMessage("ready", extensionInfo);
+ browser.test.sendMessage("ready", tabs[0]);
}
add_task(function* test_pageAction() {
const extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
"name": "PageAction Extension",
"page_action": {
@@ -67,34 +63,35 @@ add_task(function* test_pageAction() {
},
},
files: {
"extension.png": IMAGE_ARRAYBUFFER,
},
});
yield extension.startup();
- const {uuid, tab} = yield extension.awaitMessage("ready");
+ const tab = yield extension.awaitMessage("ready");
+ const uuid = `{${extension.uuid}}`;
extension.sendMessage("pageAction-show");
yield extension.awaitMessage("page-action-shown");
- ok(isPageActionShown(uuid), "The PageAction should be shown");
+ ok(PageActions.isShown(uuid), "The PageAction should be shown");
extension.sendMessage("pageAction-hide");
yield extension.awaitMessage("page-action-hidden");
- ok(!isPageActionShown(uuid), "The PageAction should be hidden");
+ ok(!PageActions.isShown(uuid), "The PageAction should be hidden");
extension.sendMessage("pageAction-show");
yield extension.awaitMessage("page-action-shown");
- ok(isPageActionShown(uuid), "The PageAction should be shown");
+ ok(PageActions.isShown(uuid), "The PageAction should be shown");
- clickPageAction(uuid);
+ PageActions.synthesizeClick(uuid);
const clickedTab = yield extension.awaitMessage("page-action-clicked");
- ok(isPageActionShown(uuid), "The PageAction should still be shown after being clicked");
+ ok(PageActions.isShown(uuid), "The PageAction should still be shown after being clicked");
is(clickedTab.id, tab.id, "Got the expected tab id in the pageAction.onClicked event");
yield extension.unload();
- ok(!isPageActionShown(uuid), "The PageAction should be removed after unload");
+ ok(!PageActions.isShown(uuid), "The PageAction should be removed after unload");
});
</script>
</body>
</html>
--- a/mobile/android/components/extensions/test/mochitest/test_ext_pageAction_popup.html
+++ b/mobile/android/components/extensions/test/mochitest/test_ext_pageAction_popup.html
@@ -12,22 +12,24 @@
<script type="text/javascript">
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
+var {PageActions} = Cu.import("resource://gre/modules/PageActions.jsm", {});
+
let dataURI = "iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAC4klEQVRYhdWXLWzbQBSADQtDAwsHC1tUhUxqfL67lk2tdn+OJg0ODU0rLByqgqINBY6tmlbn7LMTJ5FaFVVBk1G0oUGjG2jT2Y7jxmmcbU/6iJ+f36fz+e5sGP9riCGm9hB37RG+scd4Yo/wsDXCZyIE2xuXsce4bY+wXkAsQtzYmExrfFgvkJkRbkzo1ehoxx5iXcgI/9iYUGt8WH9MqDXEcmNChmEYrRCf2SHWeYgQx3x0tLNRIeKQLTtEFyJEep4NTuhk8BC+yMrwEE3+iozo42d8gK7FAOkMsRiiN8QhW2ttSK5QTfRRV4QoymVeJMvPvDp7gCZigD613MN6yRFA3SWarow9QB9LCfG+NeF9qCtjAKOSQjCqVKhfVsiHEQ+grgx/lRGqUihAc1uL8EFD+KCRO+GrF4J61phcoRoPoEzkYhZYpykh5sMb7kOdIeY+jHKur4QI4Feh4AFX1nVeLxrAvQchGsBz5ls6wa2QdwcvIcE2863bTH79KOvsz/uUYJsp+J0pSzNlDckVqqVGUAF+n6uS7txcOl6wot4JVy70ufDLy4pWLUQVPE81pRI0mGe9oxLMHSeohHvMs/STUNaUK6vDPCvOyxMFDx4achehRDJmHnydnkPww5OFfLxrGIZBFDyYl4LpMzlTQFIP6AQx86w2UeYBccFpJrcKv5L9eGDtUAU6RIELqsB74uynjy/UBRF1gS5BTFxwQT1wTiXoUg9MH7m/3NZRRoi5IJytUbMgzv4Wc832+oQkiKgEehmyMkkpKsFkQV11QsRJL5rJYBLItQgRaUZEmnoZXsomz3vGiWw+I9KMF9SVFOqZEemZekli1jN3U/UOqhHHvC6oWWGElhfSpGdOk6+O9prdwvtLj5BjRsQxdRnot+Zeifpy/2/0stktKTRNLmbk0mwXyl8253fyojj+8rxOHNAhjjm5n0/5OOCGOKBzkrMO0Z75lvSAzKlrF32Z/3z8BqLAn+yMV7VhAAAAAElFTkSuQmCC";
let image = atob(dataURI);
const IMAGE_ARRAYBUFFER = Uint8Array.from(image, byte => byte.charCodeAt(0)).buffer;
-add_task(function* test_contentscript() {
+add_task(function* test_pageAction_withPopup() {
function background() {
// TODO: Use the Tabs API to obtain the tab ids for showing pageActions.
let tabId = 1;
let onClickedListenerEnabled = false;
browser.test.onMessage.addListener((msg, details) => {
if (msg === "page-action-show") {
// TODO: switch to using .show(tabId).then(...) once bug 1270742 lands.
@@ -51,22 +53,17 @@ add_task(function* test_contentscript()
}
});
browser.pageAction.onClicked.addListener(tab => {
browser.test.assertTrue(onClickedListenerEnabled, "The onClicked listener should only fire when it is enabled.");
browser.test.sendMessage("page-action-onClicked-fired");
});
- let extensionInfo = {
- // Extract the assigned uuid from the background page url.
- uuid: `{${window.location.hostname}}`,
- };
-
- browser.test.sendMessage("ready", extensionInfo);
+ browser.test.sendMessage("ready");
}
function popupScript() {
window.onload = () => {
browser.test.sendMessage("page-action-from-popup", location.href);
};
browser.test.onMessage.addListener((msg, details) => {
if (msg == "page-action-close-popup") {
@@ -126,46 +123,47 @@ add_task(function* test_contentscript()
if (name == "") {
ok(url == name, "Calling pageAction.getPopup should return an empty string when the popup is not set.");
// The onClicked listener should get called when the popup is set to an empty string.
extension.sendMessage("page-action-enable-onClicked-listener");
yield extension.awaitMessage("page-action-onClicked-listener-enabled");
- clickPageAction(uuid);
+ PageActions.synthesizeClick(uuid);
yield extension.awaitMessage("page-action-onClicked-fired");
extension.sendMessage("page-action-disable-onClicked-listener");
yield extension.awaitMessage("page-action-onClicked-listener-disabled");
} else {
ok(url.includes(name), "Calling pageAction.getPopup should return the correct popup URL when the popup is set.");
- clickPageAction(uuid);
+ PageActions.synthesizeClick(uuid);
let location = yield extension.awaitMessage("page-action-from-popup");
ok(location.includes(name), "The popup with the correct URL should be shown.");
extension.sendMessage("page-action-close-popup", {location});
url = yield tabClosedPromise();
ok(url.includes(name), "The tab for the popup should be closed.");
}
}
yield extension.startup();
- let {uuid} = yield extension.awaitMessage("ready");
+ yield extension.awaitMessage("ready");
+ const uuid = `{${extension.uuid}}`;
extension.sendMessage("page-action-show");
yield extension.awaitMessage("page-action-shown");
- ok(isPageActionShown(uuid), "The PageAction should be shown.");
+ ok(PageActions.isShown(uuid), "The PageAction should be shown.");
yield testPopup("default.html", uuid);
yield testPopup("a.html", uuid);
yield testPopup("", uuid);
yield testPopup("b.html", uuid);
yield extension.unload();
- ok(!isPageActionShown(uuid), "The PageAction should be removed after unload.");
+ ok(!PageActions.isShown(uuid), "The PageAction should be removed after unload.");
});
</script>
</body>
</html>
--- a/testing/specialpowers/content/SpecialPowersObserverAPI.js
+++ b/testing/specialpowers/content/SpecialPowersObserverAPI.js
@@ -565,17 +565,17 @@ SpecialPowersObserverAPI.prototype = {
}
case "SPStartupExtension": {
let {ExtensionData} = Components.utils.import("resource://gre/modules/Extension.jsm", {});
let id = aMessage.data.id;
let extension = this._extensions.get(id);
extension.on("startup", () => {
- this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionSetId", args: [extension.id]});
+ this._sendReply(aMessage, "SPExtensionMessage", {id, type: "extensionSetId", args: [extension.id, extension.uuid]});
});
// Make sure the extension passes the packaging checks when
// they're run on a bare archive rather than a running instance,
// as the add-on manager runs them.
let extensionData = new ExtensionData(extension.rootURI);
extensionData.loadManifest().then(
() => {
--- a/testing/specialpowers/content/specialpowersAPI.js
+++ b/testing/specialpowers/content/specialpowersAPI.js
@@ -1993,16 +1993,17 @@ SpecialPowersAPI.prototype = {
let listener = (msg) => {
if (msg.data.id == id) {
if (msg.data.type == "extensionStarted") {
state = "running";
resolveStartup();
} else if (msg.data.type == "extensionSetId") {
extension.id = msg.data.args[0];
+ extension.uuid = msg.data.args[1];
} else if (msg.data.type == "extensionFailed") {
state = "failed";
rejectStartup("startup failed");
} else if (msg.data.type == "extensionUnloaded") {
this._extensionListeners.delete(listener);
state = "unloaded";
resolveUnload();
} else if (msg.data.type in handler) {
--- a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
+++ b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
@@ -182,16 +182,17 @@ class ExtensionWrapper {
} else if (this.state == "unloading") {
this.testScope.equal(this.state, "unloaded", "Extension not fully unloaded at test shutdown");
}
this.destroy();
});
if (extension) {
this.id = extension.id;
+ this.uuid = extension.uuid;
this.attachExtension(extension);
}
}
destroy() {
// This method should be implemented in subclasses which need to
// perform cleanup when destroyed.
}