summaryrefslogtreecommitdiffstats
path: root/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/extensions/test/browser/browser_ext_browserAction_context.js')
-rw-r--r--browser/components/extensions/test/browser/browser_ext_browserAction_context.js1194
1 files changed, 1194 insertions, 0 deletions
diff --git a/browser/components/extensions/test/browser/browser_ext_browserAction_context.js b/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
new file mode 100644
index 0000000000..c1f8184c78
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
@@ -0,0 +1,1194 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+async function runTests(options) {
+ async function background(getTests) {
+ let manifest = browser.runtime.getManifest();
+ let { manifest_version } = manifest;
+ const action = manifest_version < 3 ? "browserAction" : "action";
+ async function checkExtAPIDetails(expecting, details) {
+ let title = await browser[action].getTitle(details);
+ browser.test.assertEq(
+ expecting.title,
+ title,
+ "expected value from getTitle"
+ );
+
+ let popup = await browser[action].getPopup(details);
+ browser.test.assertEq(
+ expecting.popup,
+ popup,
+ "expected value from getPopup"
+ );
+
+ let badge = await browser[action].getBadgeText(details);
+ browser.test.assertEq(
+ expecting.badge,
+ badge,
+ "expected value from getBadge"
+ );
+
+ let badgeBackgroundColor = await browser[action].getBadgeBackgroundColor(
+ details
+ );
+ browser.test.assertEq(
+ String(expecting.badgeBackgroundColor),
+ String(badgeBackgroundColor),
+ "expected value from getBadgeBackgroundColor"
+ );
+
+ let badgeTextColor = await browser[action].getBadgeTextColor(details);
+ browser.test.assertEq(
+ String(expecting.badgeTextColor),
+ String(badgeTextColor),
+ "expected value from getBadgeTextColor"
+ );
+
+ let enabled = await browser[action].isEnabled(details);
+ browser.test.assertEq(
+ expecting.enabled,
+ enabled,
+ "expected value from isEnabled"
+ );
+ }
+
+ let tabs = [];
+ let windows = [];
+ let tests = getTests(tabs, windows);
+
+ {
+ let tabId = 0xdeadbeef;
+ let calls = [
+ () => browser[action].enable(tabId),
+ () => browser[action].disable(tabId),
+ () => browser[action].setTitle({ tabId, title: "foo" }),
+ () => browser[action].setIcon({ tabId, path: "foo.png" }),
+ () => browser[action].setPopup({ tabId, popup: "foo.html" }),
+ () => browser[action].setBadgeText({ tabId, text: "foo" }),
+ () =>
+ browser[action].setBadgeBackgroundColor({
+ tabId,
+ color: [0xff, 0, 0, 0xff],
+ }),
+ () =>
+ browser[action].setBadgeTextColor({
+ tabId,
+ color: [0, 0xff, 0xff, 0xff],
+ }),
+ ];
+
+ for (let call of calls) {
+ await browser.test.assertRejects(
+ new Promise(resolve => resolve(call())),
+ RegExp(`Invalid tab ID: ${tabId}`),
+ "Expected invalid tab ID error"
+ );
+ }
+ }
+
+ // Runs the next test in the `tests` array, checks the results,
+ // and passes control back to the outer test scope.
+ function nextTest() {
+ let test = tests.shift();
+
+ test(async (expectTab, expectWindow, expectGlobal, expectDefault) => {
+ expectGlobal = { ...expectDefault, ...expectGlobal };
+ expectWindow = { ...expectGlobal, ...expectWindow };
+ expectTab = { ...expectWindow, ...expectTab };
+
+ // Check that the API returns the expected values, and then
+ // run the next test.
+ let [{ windowId, id: tabId }] = await browser.tabs.query({
+ active: true,
+ currentWindow: true,
+ });
+ await checkExtAPIDetails(expectTab, { tabId });
+ await checkExtAPIDetails(expectWindow, { windowId });
+ await checkExtAPIDetails(expectGlobal, {});
+
+ // Check that the actual icon has the expected values, then
+ // run the next test.
+ browser.test.sendMessage("nextTest", expectTab, windowId, tests.length);
+ });
+ }
+
+ browser.test.onMessage.addListener(msg => {
+ if (msg != "runNextTest") {
+ browser.test.fail("Expecting 'runNextTest' message");
+ }
+
+ nextTest();
+ });
+
+ let [{ id, windowId }] = await browser.tabs.query({
+ active: true,
+ currentWindow: true,
+ });
+ tabs.push(id);
+ windows.push(windowId);
+ nextTest();
+ }
+
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: options.manifest,
+
+ files: options.files || {},
+
+ background: `(${background})(${options.getTests})`,
+ });
+
+ function serializeColor([r, g, b, a]) {
+ if (a === 255) {
+ return `rgb(${r}, ${g}, ${b})`;
+ }
+ return `rgba(${r}, ${g}, ${b}, ${a / 255})`;
+ }
+
+ let browserActionId;
+ async function checkWidgetDetails(details, windowId) {
+ let { document } = Services.wm.getOuterWindowWithId(windowId);
+ if (!browserActionId) {
+ browserActionId = `${makeWidgetId(extension.id)}-browser-action`;
+ }
+
+ let node = document.getElementById(browserActionId);
+ let button = node.firstElementChild;
+
+ ok(button, "button exists");
+
+ let title = details.title || options.manifest.name;
+
+ // NOTE: resorting to waitForCondition to prevent frequent
+ // intermittent failures due to multiple action API calls
+ // being queued.
+ if (getListStyleImage(button) !== details.icon) {
+ info(`wait for action icon url to be set to ${details.icon}`);
+ await TestUtils.waitForCondition(
+ () => getListStyleImage(button) === details.icon,
+ "Wait for the expected icon URL to be set"
+ );
+ }
+
+ // NOTE: resorting to waitForCondition to prevent frequent
+ // intermittent failures due to multiple action API calls
+ // being queued.
+ if (button.getAttribute("tooltiptext") !== title) {
+ info(`wait for action tooltiptext to be set to ${title}`);
+ await TestUtils.waitForCondition(
+ () => button.getAttribute("tooltiptext") === title,
+ "Wait for expected title to be set"
+ );
+ }
+
+ is(getListStyleImage(button), details.icon, "icon URL is correct");
+ is(button.getAttribute("tooltiptext"), title, "image title is correct");
+ is(button.getAttribute("label"), title, "image label is correct");
+ is(button.getAttribute("badge"), details.badge, "badge text is correct");
+ is(
+ button.getAttribute("disabled") == "true",
+ !details.enabled,
+ "disabled state is correct"
+ );
+
+ if (details.badge) {
+ let badge = button.badgeLabel;
+ let style = window.getComputedStyle(badge);
+ let expected = {
+ backgroundColor: serializeColor(details.badgeBackgroundColor),
+ color: serializeColor(details.badgeTextColor),
+ };
+ for (let [prop, value] of Object.entries(expected)) {
+ // NOTE: resorting to waitForCondition to prevent frequent
+ // intermittent failures due to multiple action API calls
+ // being queued.
+ if (style[prop] !== value) {
+ info(`wait for badge ${prop} to be set to ${value}`);
+ await TestUtils.waitForCondition(
+ () => window.getComputedStyle(badge)[prop] === value,
+ `Wait for expected badge ${prop} to be set`
+ );
+ }
+ }
+ }
+
+ // TODO: Popup URL.
+ }
+
+ let awaitFinish = new Promise(resolve => {
+ extension.onMessage(
+ "nextTest",
+ async (expecting, windowId, testsRemaining) => {
+ await promiseAnimationFrame();
+ await checkWidgetDetails(expecting, windowId);
+
+ if (testsRemaining) {
+ extension.sendMessage("runNextTest");
+ } else {
+ resolve();
+ }
+ }
+ );
+ });
+
+ await extension.startup();
+
+ await awaitFinish;
+
+ await extension.unload();
+}
+
+let tabSwitchTestData = {
+ files: {
+ "_locales/en/messages.json": {
+ popup: {
+ message: "default.html",
+ description: "Popup",
+ },
+
+ title: {
+ message: "Title",
+ description: "Title",
+ },
+ },
+
+ "default.png": imageBuffer,
+ "global.png": imageBuffer,
+ "1.png": imageBuffer,
+ "2.png": imageBuffer,
+ },
+
+ getTests: function (tabs, windows) {
+ let manifest = browser.runtime.getManifest();
+ let { manifest_version } = manifest;
+ const action = manifest_version < 3 ? "browserAction" : "action";
+
+ let details = [
+ {
+ icon: browser.runtime.getURL("default.png"),
+ popup: browser.runtime.getURL("default.html"),
+ title: "Default Title",
+ badge: "",
+ badgeBackgroundColor: [0xd9, 0, 0, 255],
+ badgeTextColor: [0xff, 0xff, 0xff, 0xff],
+ enabled: true,
+ },
+ { icon: browser.runtime.getURL("1.png") },
+ {
+ icon: browser.runtime.getURL("2.png"),
+ popup: browser.runtime.getURL("2.html"),
+ title: "Title 2",
+ badge: "2",
+ badgeBackgroundColor: [0xff, 0, 0, 0xff],
+ badgeTextColor: [0, 0xff, 0xff, 0xff],
+ enabled: false,
+ },
+ {
+ icon: browser.runtime.getURL("global.png"),
+ popup: browser.runtime.getURL("global.html"),
+ title: "Global Title",
+ badge: "g",
+ badgeBackgroundColor: [0, 0xff, 0, 0xff],
+ badgeTextColor: [0xff, 0, 0xff, 0xff],
+ enabled: false,
+ },
+ {
+ icon: browser.runtime.getURL("global.png"),
+ popup: browser.runtime.getURL("global.html"),
+ title: "Global Title",
+ badge: "g",
+ badgeBackgroundColor: [0, 0xff, 0, 0xff],
+ badgeTextColor: [0xff, 0, 0xff, 0xff],
+ },
+ ];
+
+ let promiseTabLoad = details => {
+ return new Promise(resolve => {
+ browser.tabs.onUpdated.addListener(function listener(tabId, changed) {
+ if (tabId == details.id && changed.url == details.url) {
+ browser.tabs.onUpdated.removeListener(listener);
+ resolve();
+ }
+ });
+ });
+ };
+
+ return [
+ async expect => {
+ browser.test.log("Initial state, expect default properties.");
+
+ expect(null, null, null, details[0]);
+ },
+ async expect => {
+ browser.test.log(
+ "Change the icon in the current tab. Expect default properties excluding the icon."
+ );
+ browser[action].setIcon({ tabId: tabs[0], path: "1.png" });
+
+ expect(details[1], null, null, details[0]);
+ },
+ async expect => {
+ browser.test.log("Create a new tab. Expect default properties.");
+ let tab = await browser.tabs.create({
+ active: true,
+ url: "about:blank?0",
+ });
+ tabs.push(tab.id);
+
+ browser.test.log("Await tab load.");
+ let promise = promiseTabLoad({ id: tabs[1], url: "about:blank?0" });
+ let { url } = await browser.tabs.get(tabs[1]);
+ if (url === "about:blank") {
+ await promise;
+ }
+
+ expect(null, null, null, details[0]);
+ },
+ async expect => {
+ browser.test.log("Change properties. Expect new properties.");
+ let tabId = tabs[1];
+ browser[action].setIcon({ tabId, path: "2.png" });
+ browser[action].setPopup({ tabId, popup: "2.html" });
+ browser[action].setTitle({ tabId, title: "Title 2" });
+ browser[action].setBadgeText({ tabId, text: "2" });
+ browser[action].setBadgeBackgroundColor({
+ tabId,
+ color: "#ff0000",
+ });
+ browser[action].setBadgeTextColor({ tabId, color: "#00ffff" });
+ browser[action].disable(tabId);
+
+ expect(details[2], null, null, details[0]);
+ },
+ async expect => {
+ browser.test.log(
+ "Switch back to the first tab. Expect previously set properties."
+ );
+ await browser.tabs.update(tabs[0], { active: true });
+ expect(details[1], null, null, details[0]);
+ },
+ async expect => {
+ browser.test.log(
+ "Change global values, expect those changes reflected."
+ );
+ browser[action].setIcon({ path: "global.png" });
+ browser[action].setPopup({ popup: "global.html" });
+ browser[action].setTitle({ title: "Global Title" });
+ browser[action].setBadgeText({ text: "g" });
+ browser[action].setBadgeBackgroundColor({
+ color: [0, 0xff, 0, 0xff],
+ });
+ browser[action].setBadgeTextColor({
+ color: [0xff, 0, 0xff, 0xff],
+ });
+ browser[action].disable();
+
+ expect(details[1], null, details[3], details[0]);
+ },
+ async expect => {
+ browser.test.log("Re-enable globally. Expect enabled.");
+ browser[action].enable();
+
+ expect(details[1], null, details[4], details[0]);
+ },
+ async expect => {
+ browser.test.log(
+ "Switch back to tab 2. Expect former tab values, and new global values from previous steps."
+ );
+ await browser.tabs.update(tabs[1], { active: true });
+
+ expect(details[2], null, details[4], details[0]);
+ },
+ async expect => {
+ browser.test.log(
+ "Navigate to a new page. Expect tab-specific values to be cleared."
+ );
+
+ let promise = promiseTabLoad({ id: tabs[1], url: "about:blank?1" });
+ browser.tabs.update(tabs[1], { url: "about:blank?1" });
+ await promise;
+
+ expect(null, null, details[4], details[0]);
+ },
+ async expect => {
+ browser.test.log(
+ "Delete tab, switch back to tab 1. Expect previous results again."
+ );
+ await browser.tabs.remove(tabs[1]);
+ expect(details[1], null, details[4], details[0]);
+ },
+ async expect => {
+ browser.test.log("Create a new tab. Expect new global properties.");
+ let tab = await browser.tabs.create({
+ active: true,
+ url: "about:blank?2",
+ });
+ tabs.push(tab.id);
+ expect(null, null, details[4], details[0]);
+ },
+ async expect => {
+ browser.test.log("Delete tab.");
+ await browser.tabs.remove(tabs[2]);
+ expect(details[1], null, details[4], details[0]);
+ },
+ ];
+ },
+};
+
+add_task(async function testTabSwitchContext() {
+ await runTests({
+ manifest: {
+ browser_action: {
+ default_icon: "default.png",
+ default_popup: "__MSG_popup__",
+ default_title: "Default __MSG_title__",
+ default_area: "navbar",
+ },
+
+ default_locale: "en",
+
+ permissions: ["tabs"],
+ },
+ ...tabSwitchTestData,
+ });
+});
+
+add_task(async function testTabSwitchActionContext() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["extensions.manifestV3.enabled", true]],
+ });
+
+ await runTests({
+ manifest: {
+ manifest_version: 3,
+ action: {
+ default_icon: "default.png",
+ default_popup: "__MSG_popup__",
+ default_title: "Default __MSG_title__",
+ default_area: "navbar",
+ },
+ default_locale: "en",
+ permissions: ["tabs"],
+ },
+ ...tabSwitchTestData,
+ });
+});
+
+add_task(async function testDefaultTitle() {
+ await runTests({
+ manifest: {
+ name: "Foo Extension",
+
+ browser_action: {
+ default_icon: "icon.png",
+ default_area: "navbar",
+ },
+
+ permissions: ["tabs"],
+ },
+
+ files: {
+ "icon.png": imageBuffer,
+ },
+
+ getTests: function (tabs, windows) {
+ let details = [
+ {
+ title: "Foo Extension",
+ popup: "",
+ badge: "",
+ badgeBackgroundColor: [0xd9, 0, 0, 255],
+ badgeTextColor: [0xff, 0xff, 0xff, 0xff],
+ icon: browser.runtime.getURL("icon.png"),
+ enabled: true,
+ },
+ { title: "Foo Title" },
+ { title: "Bar Title" },
+ ];
+
+ return [
+ async expect => {
+ browser.test.log("Initial state. Expect default properties.");
+
+ expect(null, null, null, details[0]);
+ },
+ async expect => {
+ browser.test.log("Change the tab title. Expect new title.");
+ browser.browserAction.setTitle({
+ tabId: tabs[0],
+ title: "Foo Title",
+ });
+
+ expect(details[1], null, null, details[0]);
+ },
+ async expect => {
+ browser.test.log("Change the global title. Expect same properties.");
+ browser.browserAction.setTitle({ title: "Bar Title" });
+
+ expect(details[1], null, details[2], details[0]);
+ },
+ async expect => {
+ browser.test.log("Clear the tab title. Expect new global title.");
+ browser.browserAction.setTitle({ tabId: tabs[0], title: null });
+
+ expect(null, null, details[2], details[0]);
+ },
+ async expect => {
+ browser.test.log("Clear the global title. Expect default title.");
+ browser.browserAction.setTitle({ title: null });
+
+ expect(null, null, null, details[0]);
+ },
+ async expect => {
+ browser.test.assertRejects(
+ browser.browserAction.setPopup({ popup: "about:addons" }),
+ /Access denied for URL about:addons/,
+ "unable to set popup to about:addons"
+ );
+
+ expect(null, null, null, details[0]);
+ },
+ ];
+ },
+ });
+});
+
+add_task(async function testBadgeColorPersistence() {
+ const extension = ExtensionTestUtils.loadExtension({
+ background() {
+ browser.test.onMessage.addListener((msg, arg) => {
+ browser.browserAction[msg](arg);
+ });
+ },
+ manifest: {
+ browser_action: {
+ default_area: "navbar",
+ },
+ },
+ });
+ await extension.startup();
+
+ function getBadgeForWindow(win) {
+ const widget = getBrowserActionWidget(extension).forWindow(win).node;
+ return widget.firstElementChild.badgeLabel;
+ }
+
+ let badge = getBadgeForWindow(window);
+ const badgeChanged = new Promise(resolve => {
+ const observer = new MutationObserver(() => resolve());
+ observer.observe(badge, { attributes: true, attributeFilter: ["style"] });
+ });
+
+ extension.sendMessage("setBadgeText", { text: "hi" });
+ extension.sendMessage("setBadgeBackgroundColor", { color: [0, 255, 0, 255] });
+
+ await badgeChanged;
+
+ is(badge.textContent, "hi", "badge text is set in first window");
+ is(
+ badge.style.backgroundColor,
+ "rgb(0, 255, 0)",
+ "badge color is set in first window"
+ );
+
+ let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
+ let win = OpenBrowserWindow();
+ await windowOpenedPromise;
+
+ badge = getBadgeForWindow(win);
+ is(badge.textContent, "hi", "badge text is set in new window");
+ is(
+ badge.style.backgroundColor,
+ "rgb(0, 255, 0)",
+ "badge color is set in new window"
+ );
+
+ await BrowserTestUtils.closeWindow(win);
+ await extension.unload();
+});
+
+add_task(async function testPropertyRemoval() {
+ await runTests({
+ manifest: {
+ name: "Generated extension",
+ browser_action: {
+ default_icon: "default.png",
+ default_popup: "default.html",
+ default_title: "Default Title",
+ default_area: "navbar",
+ },
+ },
+
+ files: {
+ "default.png": imageBuffer,
+ "global.png": imageBuffer,
+ "global2.png": imageBuffer,
+ "window.png": imageBuffer,
+ "tab.png": imageBuffer,
+ },
+
+ getTests: function (tabs, windows) {
+ let defaultIcon = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
+ let details = [
+ {
+ icon: browser.runtime.getURL("default.png"),
+ popup: browser.runtime.getURL("default.html"),
+ title: "Default Title",
+ badge: "",
+ badgeBackgroundColor: [0xd9, 0x00, 0x00, 0xff],
+ badgeTextColor: [0xff, 0xff, 0xff, 0xff],
+ enabled: true,
+ },
+ {
+ icon: browser.runtime.getURL("global.png"),
+ popup: browser.runtime.getURL("global.html"),
+ title: "global",
+ badge: "global",
+ badgeBackgroundColor: [0x11, 0x11, 0x11, 0xff],
+ badgeTextColor: [0x99, 0x99, 0x99, 0xff],
+ },
+ {
+ icon: browser.runtime.getURL("window.png"),
+ popup: browser.runtime.getURL("window.html"),
+ title: "window",
+ badge: "window",
+ badgeBackgroundColor: [0x22, 0x22, 0x22, 0xff],
+ badgeTextColor: [0x88, 0x88, 0x88, 0xff],
+ },
+ {
+ icon: browser.runtime.getURL("tab.png"),
+ popup: browser.runtime.getURL("tab.html"),
+ title: "tab",
+ badge: "tab",
+ badgeBackgroundColor: [0x33, 0x33, 0x33, 0xff],
+ badgeTextColor: [0x77, 0x77, 0x77, 0xff],
+ },
+ {
+ icon: defaultIcon,
+ popup: "",
+ title: "",
+ badge: "",
+ badgeBackgroundColor: [0x33, 0x33, 0x33, 0xff],
+ badgeTextColor: [0x77, 0x77, 0x77, 0xff],
+ },
+ {
+ icon: browser.runtime.getURL("global2.png"),
+ popup: browser.runtime.getURL("global2.html"),
+ title: "global2",
+ badge: "global2",
+ badgeBackgroundColor: [0x44, 0x44, 0x44, 0xff],
+ badgeTextColor: [0x66, 0x66, 0x66, 0xff],
+ },
+ ];
+
+ return [
+ async expect => {
+ browser.test.log("Initial state, expect default properties.");
+ expect(null, null, null, details[0]);
+ },
+ async expect => {
+ browser.test.log("Set global values, expect the new values.");
+ browser.browserAction.setIcon({ path: "global.png" });
+ browser.browserAction.setPopup({ popup: "global.html" });
+ browser.browserAction.setTitle({ title: "global" });
+ browser.browserAction.setBadgeText({ text: "global" });
+ browser.browserAction.setBadgeBackgroundColor({ color: "#111" });
+ browser.browserAction.setBadgeTextColor({ color: "#999" });
+ expect(null, null, details[1], details[0]);
+ },
+ async expect => {
+ browser.test.log("Set window values, expect the new values.");
+ let windowId = windows[0];
+ browser.browserAction.setIcon({ windowId, path: "window.png" });
+ browser.browserAction.setPopup({ windowId, popup: "window.html" });
+ browser.browserAction.setTitle({ windowId, title: "window" });
+ browser.browserAction.setBadgeText({ windowId, text: "window" });
+ browser.browserAction.setBadgeBackgroundColor({
+ windowId,
+ color: "#222",
+ });
+ browser.browserAction.setBadgeTextColor({ windowId, color: "#888" });
+ expect(null, details[2], details[1], details[0]);
+ },
+ async expect => {
+ browser.test.log("Set tab values, expect the new values.");
+ let tabId = tabs[0];
+ browser.browserAction.setIcon({ tabId, path: "tab.png" });
+ browser.browserAction.setPopup({ tabId, popup: "tab.html" });
+ browser.browserAction.setTitle({ tabId, title: "tab" });
+ browser.browserAction.setBadgeText({ tabId, text: "tab" });
+ browser.browserAction.setBadgeBackgroundColor({
+ tabId,
+ color: "#333",
+ });
+ browser.browserAction.setBadgeTextColor({ tabId, color: "#777" });
+ expect(details[3], details[2], details[1], details[0]);
+ },
+ async expect => {
+ browser.test.log(
+ "Set empty tab values, expect empty values except for colors."
+ );
+ let tabId = tabs[0];
+ browser.browserAction.setIcon({ tabId, path: "" });
+ browser.browserAction.setPopup({ tabId, popup: "" });
+ browser.browserAction.setTitle({ tabId, title: "" });
+ browser.browserAction.setBadgeText({ tabId, text: "" });
+ await browser.test.assertRejects(
+ browser.browserAction.setBadgeBackgroundColor({ tabId, color: "" }),
+ /^Invalid badge background color: ""$/,
+ "Expected invalid badge background color error"
+ );
+ await browser.test.assertRejects(
+ browser.browserAction.setBadgeTextColor({ tabId, color: "" }),
+ /^Invalid badge text color: ""$/,
+ "Expected invalid badge text color error"
+ );
+ expect(details[4], details[2], details[1], details[0]);
+ },
+ async expect => {
+ browser.test.log("Remove tab values, expect window values.");
+ let tabId = tabs[0];
+ browser.browserAction.setIcon({ tabId, path: null });
+ browser.browserAction.setPopup({ tabId, popup: null });
+ browser.browserAction.setTitle({ tabId, title: null });
+ browser.browserAction.setBadgeText({ tabId, text: null });
+ browser.browserAction.setBadgeBackgroundColor({ tabId, color: null });
+ browser.browserAction.setBadgeTextColor({ tabId, color: null });
+ expect(null, details[2], details[1], details[0]);
+ },
+ async expect => {
+ browser.test.log("Remove window values, expect global values.");
+ let windowId = windows[0];
+ browser.browserAction.setIcon({ windowId, path: null });
+ browser.browserAction.setPopup({ windowId, popup: null });
+ browser.browserAction.setTitle({ windowId, title: null });
+ browser.browserAction.setBadgeText({ windowId, text: null });
+ browser.browserAction.setBadgeBackgroundColor({
+ windowId,
+ color: null,
+ });
+ browser.browserAction.setBadgeTextColor({ windowId, color: null });
+ expect(null, null, details[1], details[0]);
+ },
+ async expect => {
+ browser.test.log("Change global values, expect the new values.");
+ browser.browserAction.setIcon({ path: "global2.png" });
+ browser.browserAction.setPopup({ popup: "global2.html" });
+ browser.browserAction.setTitle({ title: "global2" });
+ browser.browserAction.setBadgeText({ text: "global2" });
+ browser.browserAction.setBadgeBackgroundColor({ color: "#444" });
+ browser.browserAction.setBadgeTextColor({ color: "#666" });
+ expect(null, null, details[5], details[0]);
+ },
+ async expect => {
+ browser.test.log("Remove global values, expect defaults.");
+ browser.browserAction.setIcon({ path: null });
+ browser.browserAction.setPopup({ popup: null });
+ browser.browserAction.setBadgeText({ text: null });
+ browser.browserAction.setTitle({ title: null });
+ browser.browserAction.setBadgeBackgroundColor({ color: null });
+ browser.browserAction.setBadgeTextColor({ color: null });
+ expect(null, null, null, details[0]);
+ },
+ ];
+ },
+ });
+});
+
+add_task(async function testMultipleWindows() {
+ await runTests({
+ manifest: {
+ browser_action: {
+ default_icon: "default.png",
+ default_popup: "default.html",
+ default_title: "Default Title",
+ default_area: "navbar",
+ },
+ },
+
+ files: {
+ "default.png": imageBuffer,
+ "window1.png": imageBuffer,
+ "window2.png": imageBuffer,
+ },
+
+ getTests: function (tabs, windows) {
+ let details = [
+ {
+ icon: browser.runtime.getURL("default.png"),
+ popup: browser.runtime.getURL("default.html"),
+ title: "Default Title",
+ badge: "",
+ badgeBackgroundColor: [0xd9, 0x00, 0x00, 0xff],
+ badgeTextColor: [0xff, 0xff, 0xff, 0xff],
+ enabled: true,
+ },
+ {
+ icon: browser.runtime.getURL("window1.png"),
+ popup: browser.runtime.getURL("window1.html"),
+ title: "window1",
+ badge: "w1",
+ badgeBackgroundColor: [0x11, 0x11, 0x11, 0xff],
+ badgeTextColor: [0x99, 0x99, 0x99, 0xff],
+ },
+ {
+ icon: browser.runtime.getURL("window2.png"),
+ popup: browser.runtime.getURL("window2.html"),
+ title: "window2",
+ badge: "w2",
+ badgeBackgroundColor: [0x22, 0x22, 0x22, 0xff],
+ badgeTextColor: [0x88, 0x88, 0x88, 0xff],
+ },
+ { title: "tab" },
+ ];
+
+ return [
+ async expect => {
+ browser.test.log("Initial state, expect default properties.");
+ expect(null, null, null, details[0]);
+ },
+ async expect => {
+ browser.test.log("Set window values, expect the new values.");
+ let windowId = windows[0];
+ browser.browserAction.setIcon({ windowId, path: "window1.png" });
+ browser.browserAction.setPopup({ windowId, popup: "window1.html" });
+ browser.browserAction.setTitle({ windowId, title: "window1" });
+ browser.browserAction.setBadgeText({ windowId, text: "w1" });
+ browser.browserAction.setBadgeBackgroundColor({
+ windowId,
+ color: "#111",
+ });
+ browser.browserAction.setBadgeTextColor({ windowId, color: "#999" });
+ expect(null, details[1], null, details[0]);
+ },
+ async expect => {
+ browser.test.log("Create a new tab, expect window values.");
+ let tab = await browser.tabs.create({ active: true });
+ tabs.push(tab.id);
+ expect(null, details[1], null, details[0]);
+ },
+ async expect => {
+ browser.test.log("Set a tab title, expect it.");
+ await browser.browserAction.setTitle({
+ tabId: tabs[1],
+ title: "tab",
+ });
+ expect(details[3], details[1], null, details[0]);
+ },
+ async expect => {
+ browser.test.log("Open a new window, expect default values.");
+ let { id } = await browser.windows.create();
+ windows.push(id);
+ expect(null, null, null, details[0]);
+ },
+ async expect => {
+ browser.test.log("Set window values, expect the new values.");
+ let windowId = windows[1];
+ browser.browserAction.setIcon({ windowId, path: "window2.png" });
+ browser.browserAction.setPopup({ windowId, popup: "window2.html" });
+ browser.browserAction.setTitle({ windowId, title: "window2" });
+ browser.browserAction.setBadgeText({ windowId, text: "w2" });
+ browser.browserAction.setBadgeBackgroundColor({
+ windowId,
+ color: "#222",
+ });
+ browser.browserAction.setBadgeTextColor({ windowId, color: "#888" });
+ expect(null, details[2], null, details[0]);
+ },
+ async expect => {
+ browser.test.log(
+ "Move tab from old window to the new one. Tab-specific data" +
+ " is preserved but inheritance is from the new window"
+ );
+ await browser.tabs.move(tabs[1], { windowId: windows[1], index: -1 });
+ await browser.tabs.update(tabs[1], { active: true });
+ expect(details[3], details[2], null, details[0]);
+ },
+ async expect => {
+ browser.test.log("Close the initial tab of the new window.");
+ let [{ id }] = await browser.tabs.query({
+ windowId: windows[1],
+ index: 0,
+ });
+ await browser.tabs.remove(id);
+ expect(details[3], details[2], null, details[0]);
+ },
+ async expect => {
+ browser.test.log(
+ "Move the previous tab to a 3rd window, the 2nd one will close."
+ );
+ await browser.windows.create({ tabId: tabs[1] });
+ expect(details[3], null, null, details[0]);
+ },
+ async expect => {
+ browser.test.log("Close the tab, go back to the 1st window.");
+ await browser.tabs.remove(tabs[1]);
+ expect(null, details[1], null, details[0]);
+ },
+ async expect => {
+ browser.test.log(
+ "Assert failures for bad parameters. Expect no change"
+ );
+
+ let calls = {
+ setIcon: { path: "default.png" },
+ setPopup: { popup: "default.html" },
+ setTitle: { title: "Default Title" },
+ setBadgeText: { text: "" },
+ setBadgeBackgroundColor: { color: [0xd9, 0x00, 0x00, 0xff] },
+ setBadgeTextColor: { color: [0xff, 0xff, 0xff, 0xff] },
+ getPopup: {},
+ getTitle: {},
+ getBadgeText: {},
+ getBadgeBackgroundColor: {},
+ };
+ for (let [method, arg] of Object.entries(calls)) {
+ browser.test.assertThrows(
+ () => browser.browserAction[method]({ ...arg, windowId: -3 }),
+ /-3 is too small \(must be at least -2\)/,
+ method + " with invalid windowId"
+ );
+ await browser.test.assertRejects(
+ browser.browserAction[method]({
+ ...arg,
+ tabId: tabs[0],
+ windowId: windows[0],
+ }),
+ /Only one of tabId and windowId can be specified/,
+ method + " with both tabId and windowId"
+ );
+ }
+
+ expect(null, details[1], null, details[0]);
+ },
+ ];
+ },
+ });
+});
+
+add_task(async function testDefaultBadgeTextColor() {
+ await runTests({
+ manifest: {
+ browser_action: {
+ default_icon: "default.png",
+ default_popup: "default.html",
+ default_title: "Default Title",
+ default_area: "navbar",
+ },
+ },
+
+ files: {
+ "default.png": imageBuffer,
+ "window1.png": imageBuffer,
+ "window2.png": imageBuffer,
+ },
+
+ getTests: function (tabs, windows) {
+ let details = [
+ {
+ icon: browser.runtime.getURL("default.png"),
+ popup: browser.runtime.getURL("default.html"),
+ title: "Default Title",
+ badge: "",
+ badgeBackgroundColor: [0xd9, 0x00, 0x00, 0xff],
+ badgeTextColor: [0xff, 0xff, 0xff, 0xff],
+ enabled: true,
+ },
+ {
+ badgeBackgroundColor: [0xff, 0xff, 0x00, 0xff],
+ badgeTextColor: [0x00, 0x00, 0x00, 0xff],
+ },
+ {
+ badgeBackgroundColor: [0x00, 0x00, 0xff, 0xff],
+ badgeTextColor: [0xff, 0xff, 0xff, 0xff],
+ },
+ {
+ badgeBackgroundColor: [0xff, 0xff, 0xff, 0x00],
+ badgeTextColor: [0x00, 0x00, 0x00, 0xff],
+ },
+ {
+ badgeBackgroundColor: [0x00, 0x00, 0xff, 0xff],
+ badgeTextColor: [0xff, 0x00, 0xff, 0xff],
+ },
+ { badgeBackgroundColor: [0xff, 0xff, 0xff, 0x00] },
+ {
+ badgeBackgroundColor: [0x00, 0x00, 0x00, 0x00],
+ badgeTextColor: [0xff, 0xff, 0xff, 0xff],
+ },
+ ];
+
+ return [
+ async expect => {
+ browser.test.log("Initial state, expect default properties.");
+ expect(null, null, null, details[0]);
+ },
+ async expect => {
+ browser.test.log("Set a global light bgcolor, expect black text.");
+ browser.browserAction.setBadgeBackgroundColor({ color: "#ff0" });
+ expect(null, null, details[1], details[0]);
+ },
+ async expect => {
+ browser.test.log(
+ "Set a window-specific dark bgcolor, expect white text."
+ );
+ let windowId = windows[0];
+ browser.browserAction.setBadgeBackgroundColor({
+ windowId,
+ color: "#00f",
+ });
+ expect(null, details[2], details[1], details[0]);
+ },
+ async expect => {
+ browser.test.log(
+ "Set a tab-specific transparent-white bgcolor, expect black text."
+ );
+ let tabId = tabs[0];
+ browser.browserAction.setBadgeBackgroundColor({
+ tabId,
+ color: "#fff0",
+ });
+ expect(details[3], details[2], details[1], details[0]);
+ },
+ async expect => {
+ browser.test.log(
+ "Set a window-specific text color, expect it in the tab."
+ );
+ let windowId = windows[0];
+ browser.browserAction.setBadgeTextColor({ windowId, color: "#f0f" });
+ expect(details[5], details[4], details[1], details[0]);
+ },
+ async expect => {
+ browser.test.log(
+ "Remove the window-specific text color, expect black again."
+ );
+ let windowId = windows[0];
+ browser.browserAction.setBadgeTextColor({ windowId, color: null });
+ expect(details[3], details[2], details[1], details[0]);
+ },
+ async expect => {
+ browser.test.log(
+ "Set a tab-specific transparent-black bgcolor, expect white text."
+ );
+ let tabId = tabs[0];
+ browser.browserAction.setBadgeBackgroundColor({
+ tabId,
+ color: "#0000",
+ });
+ expect(details[6], details[2], details[1], details[0]);
+ },
+ ];
+ },
+ });
+});
+
+add_task(async function testNavigationClearsData() {
+ let url = "http://example.com/";
+ let default_title = "Default title";
+ let tab_title = "Tab title";
+
+ const {
+ Management: {
+ global: { tabTracker },
+ },
+ } = ChromeUtils.importESModule("resource://gre/modules/Extension.sys.mjs");
+ let extension,
+ tabs = [];
+ async function addTab(...args) {
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, ...args);
+ tabs.push(tab);
+ return tab;
+ }
+ async function sendMessage(method, param, expect, msg) {
+ extension.sendMessage({ method, param, expect, msg });
+ await extension.awaitMessage("done");
+ }
+ async function expectTabSpecificData(tab, msg) {
+ let tabId = tabTracker.getId(tab);
+ await sendMessage("getBadgeText", { tabId }, "foo", msg);
+ await sendMessage("getTitle", { tabId }, tab_title, msg);
+ }
+ async function expectDefaultData(tab, msg) {
+ let tabId = tabTracker.getId(tab);
+ await sendMessage("getBadgeText", { tabId }, "", msg);
+ await sendMessage("getTitle", { tabId }, default_title, msg);
+ }
+ async function setTabSpecificData(tab) {
+ let tabId = tabTracker.getId(tab);
+ await expectDefaultData(
+ tab,
+ "Expect default data before setting tab-specific data."
+ );
+ await sendMessage("setBadgeText", { tabId, text: "foo" });
+ await sendMessage("setTitle", { tabId, title: tab_title });
+ await expectTabSpecificData(
+ tab,
+ "Expect tab-specific data after setting it."
+ );
+ }
+
+ info("Load a tab before installing the extension");
+ let tab1 = await addTab(url, true, true);
+
+ extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ browser_action: { default_title },
+ },
+ background: function () {
+ browser.test.onMessage.addListener(
+ async ({ method, param, expect, msg }) => {
+ let result = await browser.browserAction[method](param);
+ if (expect !== undefined) {
+ browser.test.assertEq(expect, result, msg);
+ }
+ browser.test.sendMessage("done");
+ }
+ );
+ },
+ });
+ await extension.startup();
+
+ info("Set tab-specific data to the existing tab.");
+ await setTabSpecificData(tab1);
+
+ info("Add a hash. Does not cause navigation.");
+ await navigateTab(tab1, url + "#hash");
+ await expectTabSpecificData(
+ tab1,
+ "Adding a hash does not clear tab-specific data"
+ );
+
+ info("Remove the hash. Causes navigation.");
+ await navigateTab(tab1, url);
+ await expectDefaultData(tab1, "Removing hash clears tab-specific data");
+
+ info("Open a new tab, set tab-specific data to it.");
+ let tab2 = await addTab("about:newtab", false, false);
+ await setTabSpecificData(tab2);
+
+ info("Load a page in that tab.");
+ await navigateTab(tab2, url);
+ await expectDefaultData(tab2, "Loading a page clears tab-specific data.");
+
+ info("Set tab-specific data.");
+ await setTabSpecificData(tab2);
+
+ info("Push history state. Does not cause navigation.");
+ await historyPushState(tab2, url + "/path");
+ await expectTabSpecificData(
+ tab2,
+ "history.pushState() does not clear tab-specific data"
+ );
+
+ info("Navigate when the tab is not selected");
+ gBrowser.selectedTab = tab1;
+ await navigateTab(tab2, url);
+ await expectDefaultData(
+ tab2,
+ "Navigating clears tab-specific data, even when not selected."
+ );
+
+ for (let tab of tabs) {
+ await BrowserTestUtils.removeTab(tab);
+ }
+ await extension.unload();
+});