summaryrefslogtreecommitdiffstats
path: root/comm/mail/components/extensions/test/browser/browser_ext_spaces.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/components/extensions/test/browser/browser_ext_spaces.js')
-rw-r--r--comm/mail/components/extensions/test/browser/browser_ext_spaces.js1047
1 files changed, 1047 insertions, 0 deletions
diff --git a/comm/mail/components/extensions/test/browser/browser_ext_spaces.js b/comm/mail/components/extensions/test/browser/browser_ext_spaces.js
new file mode 100644
index 0000000000..16f6f4770e
--- /dev/null
+++ b/comm/mail/components/extensions/test/browser/browser_ext_spaces.js
@@ -0,0 +1,1047 @@
+/* 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/. */
+
+/**
+ * Helper Function, creates a test extension to verify expected button states.
+ *
+ * @param {Function} background - The background script executed by the test.
+ * @param {object} config - Additional config data for the test. Tests can
+ * include arbitrary data, but the following have a dedicated purpose:
+ * @param {string} selectedTheme - The selected theme (default, light or dark),
+ * used to select the expected button/menuitem icon.
+ * @param {?object} manifestIcons - The icons entry of the extension manifest.
+ * @param {?object} permissions - Permissions assigned to the extension.
+ */
+async function test_space(background, config = {}) {
+ let manifest = {
+ manifest_version: 3,
+ browser_specific_settings: {
+ gecko: {
+ id: "spaces_toolbar@mochi.test",
+ },
+ },
+ permissions: ["tabs"],
+ background: { scripts: ["utils.js", "background.js"] },
+ };
+
+ if (config.manifestIcons) {
+ manifest.icons = config.manifestIcons;
+ }
+
+ if (config.permissions) {
+ manifest.permissions = config.permissions;
+ }
+
+ let extension = ExtensionTestUtils.loadExtension({
+ files: {
+ "background.js": background,
+ "utils.js": await getUtilsJS(),
+ },
+ manifest,
+ });
+
+ extension.onMessage("checkTabs", async test => {
+ let tabmail = document.getElementById("tabmail");
+
+ if (test.action && test.spaceName && test.url) {
+ let tabPromise =
+ test.action == "switch"
+ ? BrowserTestUtils.waitForEvent(tabmail.tabContainer, "TabSelect")
+ : contentTabOpenPromise(tabmail, test.url);
+ let button = window.document.getElementById(
+ `spaces_toolbar_mochi_test-spacesButton-${test.spaceName}`
+ );
+ button.click();
+ await tabPromise;
+ }
+
+ let tabs = tabmail.tabInfo.filter(tabInfo => !!tabInfo.spaceButtonId);
+ Assert.equal(
+ test.openSpacesUrls.length,
+ tabs.length,
+ `Should have found the correct number of open add-on spaces tabs.`
+ );
+ for (let expectedUrl of test.openSpacesUrls) {
+ Assert.ok(
+ tabmail.tabInfo.find(
+ tabInfo =>
+ !!tabInfo.spaceButtonId &&
+ tabInfo.browser.currentURI.spec == expectedUrl
+ ),
+ `Should have found a spaces tab with the expected url.`
+ );
+ }
+ extension.sendMessage();
+ });
+
+ extension.onMessage("checkUI", async expected => {
+ let addonButtons = document.querySelectorAll(".spaces-addon-button");
+ Assert.equal(
+ expected.length,
+ addonButtons.length,
+ `Should have found the correct number of buttons.`
+ );
+
+ for (let {
+ name,
+ url,
+ title,
+ icons,
+ badgeText,
+ badgeBackgroundColor,
+ } of expected) {
+ // Check button.
+ let button = window.document.getElementById(
+ `spaces_toolbar_mochi_test-spacesButton-${name}`
+ );
+ Assert.ok(button, `Button for space ${name} should exist.`);
+ Assert.equal(
+ title,
+ button.title,
+ `Title of button for space ${name} should be correct.`
+ );
+
+ // Check button icon.
+ let imgStyles = window.getComputedStyle(button.querySelector("img"));
+ Assert.equal(
+ icons[config.selectedTheme],
+ imgStyles.content,
+ `Icon for button of space ${name} with theme ${config.selectedTheme} should be correct.`
+ );
+
+ // Check badge.
+ let badge = button.querySelector(".spaces-badge-container");
+ let badgeStyles = window.getComputedStyle(badge);
+ if (badgeText) {
+ Assert.equal(
+ "block",
+ badgeStyles.display,
+ `Button of space ${name} should have a badge.`
+ );
+ Assert.equal(
+ badgeText,
+ badge.textContent,
+ `Badge of button of space ${name} should have the correct content.`
+ );
+ if (badgeBackgroundColor) {
+ Assert.equal(
+ badgeBackgroundColor,
+ badgeStyles.backgroundColor,
+ `Badge of button of space ${name} should have the correct backgroundColor.`
+ );
+ }
+ } else {
+ Assert.equal(
+ "none",
+ badgeStyles.display,
+ `Button of space ${name} should not have a badge.`
+ );
+ }
+
+ let collapseButton = document.getElementById("collapseButton");
+ let revealButton = document.getElementById("spacesToolbarReveal");
+ let pinnedButton = document.getElementById("spacesPinnedButton");
+ let pinnedPopup = document.getElementById("spacesButtonMenuPopup");
+
+ Assert.ok(revealButton.hidden, "The status bar toggle button is hidden");
+ Assert.ok(pinnedButton.hidden, "The pinned titlebar button is hidden");
+ collapseButton.click();
+ Assert.ok(
+ !revealButton.hidden,
+ "The status bar toggle button is not hidden"
+ );
+ Assert.ok(
+ !pinnedButton.hidden,
+ "The pinned titlebar button is not hidden"
+ );
+ pinnedPopup.openPopup();
+
+ // Check menuitem.
+ let menuitem = window.document.getElementById(
+ `spaces_toolbar_mochi_test-spacesButton-${name}-menuitem`
+ );
+ Assert.ok(menuitem, `Menuitem for id ${name} should exist.`);
+ Assert.equal(
+ title,
+ menuitem.label,
+ `Label of menuitem of space ${name} should be correct.`
+ );
+
+ // Check menuitem icon.
+ let menuitemStyles = window.getComputedStyle(menuitem);
+ Assert.equal(
+ icons[config.selectedTheme],
+ menuitemStyles.listStyleImage,
+ `Icon of menuitem for space ${name} with theme ${config.selectedTheme} should be correct.`
+ );
+
+ pinnedPopup.hidePopup();
+ revealButton.click();
+ Assert.ok(revealButton.hidden, "The status bar toggle button is hidden");
+ Assert.ok(pinnedButton.hidden, "The pinned titlebar button is hidden");
+
+ //Check space and url.
+ let space = window.gSpacesToolbar.spaces.find(
+ space => space.name == `spaces_toolbar_mochi_test-spacesButton-${name}`
+ );
+ Assert.ok(space, "The space of this button should exists");
+ Assert.equal(
+ url,
+ space.url,
+ "The stored url of the space should be correct"
+ );
+ }
+ extension.sendMessage();
+ });
+
+ extension.onMessage("getConfig", async () => {
+ extension.sendMessage(config);
+ });
+
+ await extension.startup();
+ await extension.awaitFinish();
+ await extension.unload();
+}
+
+add_task(async function test_add_update_remove() {
+ async function background() {
+ let manifest = browser.runtime.getManifest();
+ let extensionIcon = manifest.icons
+ ? browser.runtime.getURL(manifest.icons[16])
+ : "chrome://messenger/content/extension.svg";
+
+ await window.sendMessage("checkUI", []);
+
+ // Test create().
+ browser.test.log("create(): Without id.");
+ await browser.test.assertThrows(
+ () => browser.spaces.create(),
+ /Incorrect argument types for spaces.create./,
+ "create() without name should throw."
+ );
+
+ browser.test.log("create(): Without default url.");
+ await browser.test.assertThrows(
+ () => browser.spaces.create("space_1"),
+ /Incorrect argument types for spaces.create./,
+ "create() without default url should throw."
+ );
+
+ browser.test.log("create(): With invalid default url.");
+ await browser.test.assertRejects(
+ browser.spaces.create("space_1", "invalid://url"),
+ /Failed to create space with name space_1: Invalid default url./,
+ "create() with an invalid default url should throw."
+ );
+
+ browser.test.log("create(): With default url only.");
+ let space_1 = await browser.spaces.create(
+ "space_1",
+ "https://test.invalid"
+ );
+ let expected_space_1 = {
+ name: "space_1",
+ title: "Generated extension",
+ url: "https://test.invalid",
+ icons: {
+ default: `url("${extensionIcon}")`,
+ },
+ };
+ await window.sendMessage("checkUI", [expected_space_1]);
+
+ browser.test.log("create(): With default url only, but existing id.");
+ await browser.test.assertRejects(
+ browser.spaces.create("space_1", "https://test.invalid"),
+ /Failed to create space with name space_1: Space already exists for this extension./,
+ "create() with existing id should throw."
+ );
+
+ browser.test.log("create(): With most properties.");
+ let space_2 = await browser.spaces.create("space_2", "/local/file.html", {
+ title: "Google",
+ defaultIcons: "default.png",
+ badgeText: "12",
+ badgeBackgroundColor: [50, 100, 150, 255],
+ });
+ let expected_space_2 = {
+ name: "space_2",
+ title: "Google",
+ url: browser.runtime.getURL("/local/file.html"),
+ icons: {
+ default: `url("${browser.runtime.getURL("default.png")}")`,
+ },
+ badgeText: "12",
+ badgeBackgroundColor: "rgb(50, 100, 150)",
+ };
+ await window.sendMessage("checkUI", [expected_space_1, expected_space_2]);
+
+ // Test update().
+ browser.test.log("update(): Without id.");
+ await browser.test.assertThrows(
+ () => browser.spaces.update(),
+ /Incorrect argument types for spaces.update./,
+ "update() without id should throw."
+ );
+
+ browser.test.log("update(): With invalid id.");
+ await browser.test.assertRejects(
+ browser.spaces.update(1234),
+ /Failed to update space with id 1234: Unknown id./,
+ "update() with invalid id should throw."
+ );
+
+ browser.test.log("update(): Without properties.");
+ await browser.spaces.update(space_1.id);
+ await window.sendMessage("checkUI", [expected_space_1, expected_space_2]);
+
+ browser.test.log("update(): Updating the badge.");
+ await browser.spaces.update(space_2.id, {
+ badgeText: "ok",
+ badgeBackgroundColor: "green",
+ });
+ expected_space_2.badgeText = "ok";
+ expected_space_2.badgeBackgroundColor = "rgb(0, 128, 0)";
+ await window.sendMessage("checkUI", [expected_space_1, expected_space_2]);
+
+ browser.test.log("update(): Removing the badge.");
+ await browser.spaces.update(space_2.id, {
+ badgeText: "",
+ });
+ delete expected_space_2.badgeText;
+ delete expected_space_2.badgeBackgroundColor;
+ await window.sendMessage("checkUI", [expected_space_1, expected_space_2]);
+
+ browser.test.log("update(): Changing the title.");
+ await browser.spaces.update(space_2.id, {
+ title: "Some other title",
+ });
+ expected_space_2.title = "Some other title";
+ await window.sendMessage("checkUI", [expected_space_1, expected_space_2]);
+
+ browser.test.log("update(): Removing the title.");
+ await browser.spaces.update(space_2.id, {
+ title: "",
+ });
+ expected_space_2.title = "Generated extension";
+ await window.sendMessage("checkUI", [expected_space_1, expected_space_2]);
+
+ browser.test.log("update(): Setting invalid default url.");
+ await browser.test.assertRejects(
+ browser.spaces.update(space_2.id, "invalid://url"),
+ `Failed to update space with id ${space_2.id}: Invalid default url.`,
+ "update() with invalid default url should throw."
+ );
+
+ await browser.spaces.update(space_2.id, "https://test.more.invalid", {
+ title: "Bing",
+ });
+ expected_space_2.title = "Bing";
+ expected_space_2.url = "https://test.more.invalid";
+ await window.sendMessage("checkUI", [expected_space_1, expected_space_2]);
+
+ // Test remove().
+ browser.test.log("remove(): Removing without id.");
+ await browser.test.assertThrows(
+ () => browser.spaces.remove(),
+ /Incorrect argument types for spaces.remove./,
+ "remove() without id should throw."
+ );
+
+ browser.test.log("remove(): Removing with invalid id.");
+ await browser.test.assertRejects(
+ browser.spaces.remove(1234),
+ /Failed to remove space with id 1234: Unknown id./,
+ "remove() with invalid id should throw."
+ );
+
+ browser.test.log("remove(): Removing space_1.");
+ await browser.spaces.remove(space_1.id);
+ await window.sendMessage("checkUI", [expected_space_2]);
+
+ browser.test.notifyPass();
+ }
+ await test_space(background, { selectedTheme: "default" });
+ await test_space(background, {
+ selectedTheme: "default",
+ manifestIcons: { 16: "manifest.png" },
+ });
+});
+
+add_task(async function test_open_reload_close() {
+ async function background() {
+ await window.sendMessage("checkTabs", { openSpacesUrls: [] });
+
+ // Add spaces.
+ let url1 = `http://mochi.test:8888/browser/comm/mail/components/extensions/test/browser/data/content.html`;
+ let space_1 = await browser.spaces.create("space_1", url1);
+ let url2 = `http://mochi.test:8888/browser/comm/mail/components/extensions/test/browser/data/content_body.html`;
+ let space_2 = await browser.spaces.create("space_2", url2);
+
+ // Open spaces.
+ await window.sendMessage("checkTabs", {
+ action: "open",
+ url: url1,
+ spaceName: "space_1",
+ openSpacesUrls: [url1],
+ });
+ await window.sendMessage("checkTabs", {
+ action: "open",
+ url: url2,
+ spaceName: "space_2",
+ openSpacesUrls: [url1, url2],
+ });
+
+ // Switch to open spaces tab.
+ await window.sendMessage("checkTabs", {
+ action: "switch",
+ url: url1,
+ spaceName: "space_1",
+ openSpacesUrls: [url1, url2],
+ });
+ await window.sendMessage("checkTabs", {
+ action: "switch",
+ url: url2,
+ spaceName: "space_2",
+ openSpacesUrls: [url1, url2],
+ });
+
+ // TODO: Add test for tab reloading, once this has been implemented.
+
+ // Remove spaces and check that related spaces tab are closed.
+ await browser.spaces.remove(space_1.id);
+ await window.sendMessage("checkTabs", { openSpacesUrls: [url2] });
+ await browser.spaces.remove(space_2.id);
+ await window.sendMessage("checkTabs", { openSpacesUrls: [] });
+
+ browser.test.notifyPass();
+ }
+ await test_space(background, { selectedTheme: "default" });
+});
+
+add_task(async function test_icons() {
+ async function background() {
+ let manifest = browser.runtime.getManifest();
+ let extensionIcon = manifest.icons
+ ? browser.runtime.getURL(manifest.icons[16])
+ : "chrome://messenger/content/extension.svg";
+
+ // Test 1: Setting defaultIcons and themeIcons.
+ browser.test.log("create(): Setting defaultIcons and themeIcons.");
+ let space_1 = await browser.spaces.create(
+ "space_1",
+ "https://test.invalid",
+ {
+ title: "Google",
+ defaultIcons: "default.png",
+ themeIcons: [
+ {
+ dark: "dark.png",
+ light: "light.png",
+ size: 16,
+ },
+ ],
+ }
+ );
+ let expected_space_1 = {
+ name: "space_1",
+ title: "Google",
+ url: "https://test.invalid",
+ icons: {
+ default: `url("${browser.runtime.getURL("default.png")}")`,
+ dark: `url("${browser.runtime.getURL("dark.png")}")`,
+ light: `url("${browser.runtime.getURL("light.png")}")`,
+ },
+ };
+ await window.sendMessage("checkUI", [expected_space_1]);
+
+ // Clearing defaultIcons.
+ await browser.spaces.update(space_1.id, {
+ defaultIcons: "",
+ });
+ expected_space_1.icons = {
+ default: `url("${browser.runtime.getURL("dark.png")}")`,
+ dark: `url("${browser.runtime.getURL("dark.png")}")`,
+ light: `url("${browser.runtime.getURL("light.png")}")`,
+ };
+ await window.sendMessage("checkUI", [expected_space_1]);
+
+ // Setting other defaultIcons.
+ await browser.spaces.update(space_1.id, {
+ defaultIcons: "other.png",
+ });
+ expected_space_1.icons = {
+ default: `url("${browser.runtime.getURL("other.png")}")`,
+ dark: `url("${browser.runtime.getURL("dark.png")}")`,
+ light: `url("${browser.runtime.getURL("light.png")}")`,
+ };
+ await window.sendMessage("checkUI", [expected_space_1]);
+
+ // Clearing themeIcons.
+ await browser.spaces.update(space_1.id, {
+ themeIcons: [],
+ });
+ expected_space_1.icons = {
+ default: `url("${browser.runtime.getURL("other.png")}")`,
+ dark: `url("${browser.runtime.getURL("other.png")}")`,
+ light: `url("${browser.runtime.getURL("other.png")}")`,
+ };
+ await window.sendMessage("checkUI", [expected_space_1]);
+
+ // Setting other themeIcons.
+ await browser.spaces.update(space_1.id, {
+ themeIcons: [
+ {
+ dark: "dark2.png",
+ light: "light2.png",
+ size: 16,
+ },
+ ],
+ });
+ expected_space_1.icons = {
+ default: `url("${browser.runtime.getURL("other.png")}")`,
+ dark: `url("${browser.runtime.getURL("dark2.png")}")`,
+ light: `url("${browser.runtime.getURL("light2.png")}")`,
+ };
+ await window.sendMessage("checkUI", [expected_space_1]);
+
+ // Test 2: Setting themeIcons only.
+ browser.test.log("create(): Setting themeIcons only.");
+ let space_2 = await browser.spaces.create(
+ "space_2",
+ "https://test.other.invalid",
+ {
+ title: "Wikipedia",
+ themeIcons: [
+ {
+ dark: "dark2.png",
+ light: "light2.png",
+ size: 16,
+ },
+ ],
+ }
+ );
+ // Not specifying defaultIcons but only themeIcons should always use the
+ // theme icons, even for the default theme (and not the extension icon).
+ let expected_space_2 = {
+ name: "space_2",
+ title: "Wikipedia",
+ url: "https://test.other.invalid",
+ icons: {
+ default: `url("${browser.runtime.getURL("dark2.png")}")`,
+ dark: `url("${browser.runtime.getURL("dark2.png")}")`,
+ light: `url("${browser.runtime.getURL("light2.png")}")`,
+ },
+ };
+ await window.sendMessage("checkUI", [expected_space_1, expected_space_2]);
+
+ // Clearing themeIcons.
+ await browser.spaces.update(space_2.id, {
+ themeIcons: [],
+ });
+ expected_space_2.icons = {
+ default: `url("${extensionIcon}")`,
+ dark: `url("${extensionIcon}")`,
+ light: `url("${extensionIcon}")`,
+ };
+ await window.sendMessage("checkUI", [expected_space_1, expected_space_2]);
+
+ // Test 3: Setting defaultIcons only.
+ browser.test.log("create(): Setting defaultIcons only.");
+ let space_3 = await browser.spaces.create(
+ "space_3",
+ "https://test.more.invalid",
+ {
+ title: "Bing",
+ defaultIcons: "default.png",
+ }
+ );
+ let expected_space_3 = {
+ name: "space_3",
+ title: "Bing",
+ url: "https://test.more.invalid",
+ icons: {
+ default: `url("${browser.runtime.getURL("default.png")}")`,
+ dark: `url("${browser.runtime.getURL("default.png")}")`,
+ light: `url("${browser.runtime.getURL("default.png")}")`,
+ },
+ };
+ await window.sendMessage("checkUI", [
+ expected_space_1,
+ expected_space_2,
+ expected_space_3,
+ ]);
+
+ // Clearing defaultIcons and setting themeIcons.
+ await browser.spaces.update(space_3.id, {
+ defaultIcons: "",
+ themeIcons: [
+ {
+ dark: "dark3.png",
+ light: "light3.png",
+ size: 16,
+ },
+ ],
+ });
+ expected_space_3.icons = {
+ default: `url("${browser.runtime.getURL("dark3.png")}")`,
+ dark: `url("${browser.runtime.getURL("dark3.png")}")`,
+ light: `url("${browser.runtime.getURL("light3.png")}")`,
+ };
+ await window.sendMessage("checkUI", [
+ expected_space_1,
+ expected_space_2,
+ expected_space_3,
+ ]);
+
+ // Test 4: Setting no icons.
+ browser.test.log("create(): Setting no icons.");
+ let space_4 = await browser.spaces.create(
+ "space_4",
+ "https://duckduckgo.com",
+ {
+ title: "DuckDuckGo",
+ }
+ );
+ let expected_space_4 = {
+ name: "space_4",
+ title: "DuckDuckGo",
+ url: "https://duckduckgo.com",
+ icons: {
+ default: `url("${extensionIcon}")`,
+ dark: `url("${extensionIcon}")`,
+ light: `url("${extensionIcon}")`,
+ },
+ };
+ await window.sendMessage("checkUI", [
+ expected_space_1,
+ expected_space_2,
+ expected_space_3,
+ expected_space_4,
+ ]);
+
+ // Setting and clearing default icons.
+ await browser.spaces.update(space_4.id, {
+ defaultIcons: "default.png",
+ });
+ expected_space_4.icons = {
+ default: `url("${browser.runtime.getURL("default.png")}")`,
+ dark: `url("${browser.runtime.getURL("default.png")}")`,
+ light: `url("${browser.runtime.getURL("default.png")}")`,
+ };
+ await window.sendMessage("checkUI", [
+ expected_space_1,
+ expected_space_2,
+ expected_space_3,
+ expected_space_4,
+ ]);
+ await browser.spaces.update(space_4.id, {
+ defaultIcons: "",
+ });
+ expected_space_4.icons = {
+ default: `url("${extensionIcon}")`,
+ dark: `url("${extensionIcon}")`,
+ light: `url("${extensionIcon}")`,
+ };
+ await window.sendMessage("checkUI", [
+ expected_space_1,
+ expected_space_2,
+ expected_space_3,
+ expected_space_4,
+ ]);
+
+ browser.test.notifyPass();
+ }
+
+ // Test with and without icons defined in the manifest.
+ for (let manifestIcons of [null, { 16: "manifest16.png" }]) {
+ let dark_theme = await AddonManager.getAddonByID(
+ "thunderbird-compact-dark@mozilla.org"
+ );
+ await dark_theme.enable();
+ await test_space(background, { selectedTheme: "light", manifestIcons });
+
+ let light_theme = await AddonManager.getAddonByID(
+ "thunderbird-compact-light@mozilla.org"
+ );
+ await light_theme.enable();
+ await test_space(background, { selectedTheme: "dark", manifestIcons });
+
+ // Disabling a theme will enable the default theme.
+ await light_theme.disable();
+ await test_space(background, { selectedTheme: "default", manifestIcons });
+ }
+});
+
+add_task(async function test_open_programmatically() {
+ async function background() {
+ await window.sendMessage("checkTabs", { openSpacesUrls: [] });
+
+ // Add spaces.
+ let url1 = `http://mochi.test:8888/browser/comm/mail/components/extensions/test/browser/data/content.html`;
+ let space_1 = await browser.spaces.create("space_1", url1);
+ let url2 = `http://mochi.test:8888/browser/comm/mail/components/extensions/test/browser/data/content_body.html`;
+ let space_2 = await browser.spaces.create("space_2", url2);
+ await window.sendMessage("checkTabs", { openSpacesUrls: [] });
+
+ async function openSpace(space, url) {
+ let loadPromise = new Promise(resolve => {
+ let urlSeen = false;
+ let listener = (tabId, changeInfo) => {
+ if (changeInfo.url && changeInfo.url == url) {
+ urlSeen = true;
+ }
+ if (changeInfo.status == "complete" && urlSeen) {
+ browser.tabs.onUpdated.removeListener(listener);
+ resolve();
+ }
+ };
+ browser.tabs.onUpdated.addListener(listener);
+ });
+ let tab = await browser.spaces.open(space.id);
+ await loadPromise;
+
+ browser.test.assertEq(
+ space.id,
+ tab.spaceId,
+ "The opened tab should belong to the correct space"
+ );
+
+ let queriedTabs = await browser.tabs.query({ spaceId: space.id });
+ browser.test.assertEq(
+ 1,
+ queriedTabs.length,
+ "browser.tabs.query() should find exactly one tab belonging to the opened space"
+ );
+ browser.test.assertEq(
+ tab.id,
+ queriedTabs[0].id,
+ "browser.tabs.query() should find the correct tab belonging to the opened space"
+ );
+ }
+
+ // Open space #1.
+ await openSpace(space_1, url1);
+ await window.sendMessage("checkTabs", {
+ spaceName: "space_1",
+ openSpacesUrls: [url1],
+ });
+
+ // Open space #2.
+ await openSpace(space_2, url2);
+ await window.sendMessage("checkTabs", {
+ spaceName: "space_2",
+ openSpacesUrls: [url1, url2],
+ });
+
+ // Switch to open space tab.
+ await window.sendMessage("checkTabs", {
+ action: "switch",
+ url: url1,
+ spaceName: "space_1",
+ openSpacesUrls: [url1, url2],
+ });
+
+ await window.sendMessage("checkTabs", {
+ action: "switch",
+ url: url2,
+ spaceName: "space_2",
+ openSpacesUrls: [url1, url2],
+ });
+
+ // Remove spaces and check that related spaces tab are closed.
+ await browser.spaces.remove(space_1.id);
+ await window.sendMessage("checkTabs", { openSpacesUrls: [url2] });
+ await browser.spaces.remove(space_2.id);
+ await window.sendMessage("checkTabs", { openSpacesUrls: [] });
+
+ browser.test.notifyPass();
+ }
+ await test_space(background, { selectedTheme: "default" });
+});
+
+// Load a second extension parallel to the standard space test, which creates
+// two additional spaces.
+async function test_query({ permissions }) {
+ async function query_background() {
+ function verify(description, expected, spaces) {
+ browser.test.assertEq(
+ expected.length,
+ spaces.length,
+ `${description}: Should find the correct number of spaces`
+ );
+ window.assertDeepEqual(
+ spaces,
+ expected,
+ `${description}: Should find the correct spaces`
+ );
+ }
+
+ async function query(queryInfo, expected) {
+ let spaces =
+ queryInfo === null
+ ? await browser.spaces.query()
+ : await browser.spaces.query(queryInfo);
+ verify(`Query ${JSON.stringify(queryInfo)}`, expected, spaces);
+ }
+
+ let builtIn = [
+ {
+ id: 1,
+ name: "mail",
+ isBuiltIn: true,
+ isSelfOwned: false,
+ },
+ {
+ id: 2,
+ isBuiltIn: true,
+ isSelfOwned: false,
+ name: "addressbook",
+ },
+ {
+ id: 3,
+ isBuiltIn: true,
+ isSelfOwned: false,
+ name: "calendar",
+ },
+ {
+ id: 4,
+ isBuiltIn: true,
+ isSelfOwned: false,
+ name: "tasks",
+ },
+ {
+ id: 5,
+ isBuiltIn: true,
+ isSelfOwned: false,
+ name: "chat",
+ },
+ {
+ id: 6,
+ isBuiltIn: true,
+ isSelfOwned: false,
+ name: "settings",
+ },
+ ];
+
+ await window.sendMessage("checkTabs", { openSpacesUrls: [] });
+ let [{ other_1, other_11, permissions }] = await window.sendMessage(
+ "getConfig"
+ );
+ let hasManagement = permissions && permissions.includes("management");
+
+ // Verify space_1 from other extension.
+ let expected_other_1 = {
+ name: "space_1",
+ isBuiltIn: false,
+ isSelfOwned: true,
+ };
+ if (hasManagement) {
+ expected_other_1.extensionId = "spaces_toolbar_other@mochi.test";
+ }
+ verify("Check space_1 from other extension", other_1, expected_other_1);
+
+ // Verify space_11 from other extension.
+ let expected_other_11 = {
+ name: "space_11",
+ isBuiltIn: false,
+ isSelfOwned: true,
+ };
+ if (hasManagement) {
+ expected_other_11.extensionId = "spaces_toolbar_other@mochi.test";
+ }
+ verify("Check space_11 from other extension", other_11, expected_other_11);
+
+ // Manipulate isSelfOwned, because we got those from the other extension.
+ other_1.isSelfOwned = false;
+ other_11.isSelfOwned = false;
+
+ await query(null, [...builtIn, other_1, other_11]);
+ await query({}, [...builtIn, other_1, other_11]);
+ await query({ isSelfOwned: false }, [...builtIn, other_1, other_11]);
+ await query({ isBuiltIn: true }, [...builtIn]);
+ await query({ isBuiltIn: false }, [other_1, other_11]);
+ await query({ isSelfOwned: true }, []);
+ await query(
+ { extensionId: "spaces_toolbar_other@mochi.test" },
+ hasManagement ? [other_1, other_11] : []
+ );
+
+ // Add spaces.
+ let url1 = `http://mochi.test:8888/browser/comm/mail/components/extensions/test/browser/data/content.html`;
+ let space_1 = await browser.spaces.create("space_1", url1);
+ let url2 = `http://mochi.test:8888/browser/comm/mail/components/extensions/test/browser/data/content_body.html`;
+ let space_2 = await browser.spaces.create("space_2", url2);
+
+ // Verify returned space_1
+ let expected_space_1 = {
+ name: "space_1",
+ isBuiltIn: false,
+ isSelfOwned: true,
+ };
+ if (hasManagement) {
+ expected_space_1.extensionId = "spaces_toolbar@mochi.test";
+ }
+ verify("Check space_1", space_1, expected_space_1);
+
+ // Verify returned space_2
+ let expected_space_2 = {
+ name: "space_2",
+ isBuiltIn: false,
+ isSelfOwned: true,
+ };
+ if (hasManagement) {
+ expected_space_2.extensionId = "spaces_toolbar@mochi.test";
+ }
+ verify("Check space_2", space_2, expected_space_2);
+
+ await query(null, [...builtIn, other_1, other_11, space_1, space_2]);
+ await query({ isSelfOwned: false }, [...builtIn, other_1, other_11]);
+ await query({ isBuiltIn: true }, [...builtIn]);
+ await query({ isBuiltIn: false }, [other_1, other_11, space_1, space_2]);
+ await query({ isSelfOwned: true }, [space_1, space_2]);
+ await query(
+ { extensionId: "spaces_toolbar_other@mochi.test" },
+ hasManagement ? [other_1, other_11] : []
+ );
+ await query(
+ { extensionId: "spaces_toolbar@mochi.test" },
+ hasManagement ? [space_1, space_2] : []
+ );
+
+ await query({ id: space_1.id }, [space_1]);
+ await query({ id: other_1.id }, [other_1]);
+ await query({ id: space_2.id }, [space_2]);
+ await query({ id: other_11.id }, [other_11]);
+ await query({ name: "space_1" }, [other_1, space_1]);
+ await query({ name: "space_2" }, [space_2]);
+ await query({ name: "space_11" }, [other_11]);
+
+ browser.test.notifyPass();
+ }
+
+ let otherExtension = ExtensionTestUtils.loadExtension({
+ files: {
+ "background.js": async () => {
+ let url = `http://mochi.test:8888/browser/comm/mail/components/extensions/test/browser/data/content.html`;
+ let other_1 = await browser.spaces.create("space_1", url);
+ let other_11 = await browser.spaces.create("space_11", url);
+ browser.test.sendMessage("Done", { other_1, other_11 });
+ browser.test.notifyPass();
+ },
+ "utils.js": await getUtilsJS(),
+ },
+ manifest: {
+ manifest_version: 3,
+ browser_specific_settings: {
+ gecko: {
+ id: "spaces_toolbar_other@mochi.test",
+ },
+ },
+ permissions,
+ background: { scripts: ["utils.js", "background.js"] },
+ },
+ });
+
+ await otherExtension.startup();
+ let { other_1, other_11 } = await otherExtension.awaitMessage("Done");
+
+ await test_space(query_background, {
+ selectedTheme: "default",
+ other_1,
+ other_11,
+ permissions,
+ });
+
+ await otherExtension.awaitFinish();
+ await otherExtension.unload();
+}
+
+add_task(async function test_query_no_management_permission() {
+ await test_query({ permissions: [] });
+});
+
+add_task(async function test_query_management_permission() {
+ await test_query({ permissions: ["management"] });
+});
+
+// Test built-in spaces to make sure the space definition of the spaceTracker in
+// ext-mails.js is matching the actual space definition in spacesToolbar.js
+add_task(async function test_builtIn_spaces() {
+ let extension = ExtensionTestUtils.loadExtension({
+ files: {
+ "background.js": async () => {
+ const checkSpace = async (spaceId, spaceName) => {
+ let spaces = await browser.spaces.query({ id: spaceId });
+ browser.test.assertEq(spaces.length, 1, "Should find a single space");
+ browser.test.assertEq(
+ spaces[0].isBuiltIn,
+ true,
+ "Should find a built-in space"
+ );
+ browser.test.assertEq(
+ spaces[0].name,
+ spaceName,
+ "Should find the correct space"
+ );
+ };
+
+ // Test the already open mail space.
+
+ let mailTabs = await browser.tabs.query({ type: "mail" });
+ browser.test.assertEq(
+ mailTabs.length,
+ 1,
+ "Should find a single mail tab"
+ );
+ await checkSpace(mailTabs[0].spaceId, "mail");
+
+ // Test all other spaces.
+
+ let builtInSpaces = [
+ "addressbook",
+ "calendar",
+ "tasks",
+ "chat",
+ "settings",
+ ];
+
+ for (let spaceName of builtInSpaces) {
+ await new Promise(resolve => {
+ const listener = async tab => {
+ await checkSpace(tab.spaceId, spaceName);
+ browser.tabs.remove(tab.id);
+ browser.tabs.onCreated.removeListener(listener);
+ resolve();
+ };
+ browser.tabs.onCreated.addListener(listener);
+ browser.test.sendMessage("openSpace", spaceName);
+ });
+ }
+
+ browser.test.notifyPass();
+ },
+ "utils.js": await getUtilsJS(),
+ },
+ manifest: {
+ manifest_version: 2,
+ browser_specific_settings: {
+ gecko: {
+ id: "built-in-spaces@mochi.test",
+ },
+ },
+ background: { scripts: ["utils.js", "background.js"] },
+ },
+ });
+
+ extension.onMessage("openSpace", async spaceName => {
+ window.gSpacesToolbar.openSpace(
+ window.document.getElementById("tabmail"),
+ window.gSpacesToolbar.spaces.find(space => space.name == spaceName)
+ );
+ });
+
+ await extension.startup();
+ await extension.awaitFinish();
+ await extension.unload();
+});