summaryrefslogtreecommitdiffstats
path: root/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js')
-rw-r--r--browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js442
1 files changed, 442 insertions, 0 deletions
diff --git a/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js b/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js
new file mode 100644
index 0000000000..a4b01bc182
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_runtime_openOptionsPage.js
@@ -0,0 +1,442 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+async function loadExtension(options) {
+ let extension = ExtensionTestUtils.loadExtension({
+ useAddonManager: "temporary",
+
+ manifest: Object.assign(
+ {
+ permissions: ["tabs"],
+ },
+ options.manifest
+ ),
+
+ files: {
+ "options.html": `<!DOCTYPE html>
+ <html>
+ <head>
+ <meta charset="utf-8">
+ <script src="options.js" type="text/javascript"></script>
+ </head>
+ </html>`,
+
+ "options.js": function () {
+ window.iAmOption = true;
+ browser.runtime.sendMessage("options.html");
+ browser.runtime.onMessage.addListener((msg, sender, respond) => {
+ if (msg == "ping") {
+ respond("pong");
+ } else if (msg == "connect") {
+ let port = browser.runtime.connect();
+ port.postMessage("ping-from-options-html");
+ port.onMessage.addListener(msg => {
+ if (msg == "ping-from-bg") {
+ browser.test.log("Got outbound options.html pong");
+ browser.test.sendMessage("options-html-outbound-pong");
+ }
+ });
+ }
+ });
+
+ browser.runtime.onConnect.addListener(port => {
+ browser.test.log("Got inbound options.html port");
+
+ port.postMessage("ping-from-options-html");
+ port.onMessage.addListener(msg => {
+ if (msg == "ping-from-bg") {
+ browser.test.log("Got inbound options.html pong");
+ browser.test.sendMessage("options-html-inbound-pong");
+ }
+ });
+ });
+ },
+ },
+
+ background: options.background,
+ });
+
+ await extension.startup();
+
+ return extension;
+}
+
+add_task(async function run_test_inline_options() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "http://example.com/"
+ );
+
+ let extension = await loadExtension({
+ manifest: {
+ browser_specific_settings: {
+ gecko: { id: "inline_options@tests.mozilla.org" },
+ },
+ options_ui: {
+ page: "options.html",
+ },
+ },
+
+ background: async function () {
+ let _optionsPromise;
+ let awaitOptions = () => {
+ browser.test.assertFalse(
+ _optionsPromise,
+ "Should not be awaiting options already"
+ );
+
+ return new Promise(resolve => {
+ _optionsPromise = { resolve };
+ });
+ };
+
+ browser.runtime.onMessage.addListener((msg, sender) => {
+ if (msg == "options.html") {
+ if (_optionsPromise) {
+ _optionsPromise.resolve(sender.tab);
+ _optionsPromise = null;
+ } else {
+ browser.test.fail("Saw unexpected options page load");
+ }
+ }
+ });
+
+ try {
+ let [firstTab] = await browser.tabs.query({
+ currentWindow: true,
+ active: true,
+ });
+
+ browser.test.log("Open options page. Expect fresh load.");
+
+ let [, optionsTab] = await Promise.all([
+ browser.runtime.openOptionsPage(),
+ awaitOptions(),
+ ]);
+
+ browser.test.assertEq(
+ "about:addons",
+ optionsTab.url,
+ "Tab contains AddonManager"
+ );
+ browser.test.assertTrue(optionsTab.active, "Tab is active");
+ browser.test.assertTrue(
+ optionsTab.id != firstTab.id,
+ "Tab is a new tab"
+ );
+
+ browser.test.assertEq(
+ 0,
+ browser.extension.getViews({ type: "popup" }).length,
+ "viewType is not popup"
+ );
+ browser.test.assertEq(
+ 1,
+ browser.extension.getViews({ type: "tab" }).length,
+ "viewType is tab"
+ );
+ browser.test.assertEq(
+ 1,
+ browser.extension.getViews({ windowId: optionsTab.windowId }).length,
+ "windowId matches"
+ );
+
+ let views = browser.extension.getViews();
+ browser.test.assertEq(
+ 2,
+ views.length,
+ "Expected the options page and the background page"
+ );
+ browser.test.assertTrue(
+ views.includes(window),
+ "One of the views is the background page"
+ );
+ browser.test.assertTrue(
+ views.some(w => w.iAmOption),
+ "One of the views is the options page"
+ );
+
+ browser.test.log("Switch tabs.");
+ await browser.tabs.update(firstTab.id, { active: true });
+
+ browser.test.log(
+ "Open options page again. Expect tab re-selected, no new load."
+ );
+
+ await browser.runtime.openOptionsPage();
+ let [tab] = await browser.tabs.query({
+ currentWindow: true,
+ active: true,
+ });
+
+ browser.test.assertEq(
+ optionsTab.id,
+ tab.id,
+ "Tab is the same as the previous options tab"
+ );
+ browser.test.assertEq(
+ "about:addons",
+ tab.url,
+ "Tab contains AddonManager"
+ );
+
+ browser.test.log("Ping options page.");
+ let pong = await browser.runtime.sendMessage("ping");
+ browser.test.assertEq("pong", pong, "Got pong.");
+
+ let done = new Promise(resolve => {
+ browser.test.onMessage.addListener(msg => {
+ if (msg == "ports-done") {
+ resolve();
+ }
+ });
+ });
+
+ browser.runtime.onConnect.addListener(port => {
+ browser.test.log("Got inbound background port");
+
+ port.postMessage("ping-from-bg");
+ port.onMessage.addListener(msg => {
+ if (msg == "ping-from-options-html") {
+ browser.test.log("Got inbound background pong");
+ browser.test.sendMessage("bg-inbound-pong");
+ }
+ });
+ });
+
+ browser.runtime.sendMessage("connect");
+
+ let port = browser.runtime.connect();
+ port.postMessage("ping-from-bg");
+ port.onMessage.addListener(msg => {
+ if (msg == "ping-from-options-html") {
+ browser.test.log("Got outbound background pong");
+ browser.test.sendMessage("bg-outbound-pong");
+ }
+ });
+
+ await done;
+
+ browser.test.log("Remove options tab.");
+ await browser.tabs.remove(optionsTab.id);
+
+ browser.test.log("Open options page again. Expect fresh load.");
+ [, tab] = await Promise.all([
+ browser.runtime.openOptionsPage(),
+ awaitOptions(),
+ ]);
+ browser.test.assertEq(
+ "about:addons",
+ tab.url,
+ "Tab contains AddonManager"
+ );
+ browser.test.assertTrue(tab.active, "Tab is active");
+ browser.test.assertTrue(tab.id != optionsTab.id, "Tab is a new tab");
+
+ await browser.tabs.remove(tab.id);
+
+ browser.test.notifyPass("options-ui");
+ } catch (error) {
+ browser.test.fail(`Error: ${error} :: ${error.stack}`);
+ browser.test.notifyFail("options-ui");
+ }
+ },
+ });
+
+ await Promise.all([
+ extension.awaitMessage("options-html-inbound-pong"),
+ extension.awaitMessage("options-html-outbound-pong"),
+ extension.awaitMessage("bg-inbound-pong"),
+ extension.awaitMessage("bg-outbound-pong"),
+ ]);
+
+ extension.sendMessage("ports-done");
+
+ await extension.awaitFinish("options-ui");
+
+ await extension.unload();
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_tab_options() {
+ info(`Test options opened in a tab`);
+
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "http://example.com/"
+ );
+
+ let extension = await loadExtension({
+ manifest: {
+ browser_specific_settings: {
+ gecko: { id: "tab_options@tests.mozilla.org" },
+ },
+ options_ui: {
+ page: "options.html",
+ open_in_tab: true,
+ },
+ },
+
+ background: async function () {
+ let _optionsPromise;
+ let awaitOptions = () => {
+ browser.test.assertFalse(
+ _optionsPromise,
+ "Should not be awaiting options already"
+ );
+
+ return new Promise(resolve => {
+ _optionsPromise = { resolve };
+ });
+ };
+
+ browser.runtime.onMessage.addListener((msg, sender) => {
+ if (msg == "options.html") {
+ if (_optionsPromise) {
+ _optionsPromise.resolve(sender.tab);
+ _optionsPromise = null;
+ } else {
+ browser.test.fail("Saw unexpected options page load");
+ }
+ }
+ });
+
+ let optionsURL = browser.runtime.getURL("options.html");
+
+ try {
+ let [firstTab] = await browser.tabs.query({
+ currentWindow: true,
+ active: true,
+ });
+
+ browser.test.log("Open options page. Expect fresh load.");
+ let [, optionsTab] = await Promise.all([
+ browser.runtime.openOptionsPage(),
+ awaitOptions(),
+ ]);
+ browser.test.assertEq(
+ optionsURL,
+ optionsTab.url,
+ "Tab contains options.html"
+ );
+ browser.test.assertTrue(optionsTab.active, "Tab is active");
+ browser.test.assertTrue(
+ optionsTab.id != firstTab.id,
+ "Tab is a new tab"
+ );
+
+ browser.test.assertEq(
+ 0,
+ browser.extension.getViews({ type: "popup" }).length,
+ "viewType is not popup"
+ );
+ browser.test.assertEq(
+ 1,
+ browser.extension.getViews({ type: "tab" }).length,
+ "viewType is tab"
+ );
+ browser.test.assertEq(
+ 1,
+ browser.extension.getViews({ windowId: optionsTab.windowId }).length,
+ "windowId matches"
+ );
+
+ let views = browser.extension.getViews();
+ browser.test.assertEq(
+ 2,
+ views.length,
+ "Expected the options page and the background page"
+ );
+ browser.test.assertTrue(
+ views.includes(window),
+ "One of the views is the background page"
+ );
+ browser.test.assertTrue(
+ views.some(w => w.iAmOption),
+ "One of the views is the options page"
+ );
+
+ browser.test.log("Switch tabs.");
+ await browser.tabs.update(firstTab.id, { active: true });
+
+ browser.test.log(
+ "Open options page again. Expect tab re-selected, no new load."
+ );
+
+ await browser.runtime.openOptionsPage();
+ let [tab] = await browser.tabs.query({
+ currentWindow: true,
+ active: true,
+ });
+
+ browser.test.assertEq(
+ optionsTab.id,
+ tab.id,
+ "Tab is the same as the previous options tab"
+ );
+ browser.test.assertEq(optionsURL, tab.url, "Tab contains options.html");
+
+ // Unfortunately, we can't currently do this, since onMessage doesn't
+ // currently support responses when there are multiple listeners.
+ //
+ // browser.test.log("Ping options page.");
+ // return new Promise(resolve => browser.runtime.sendMessage("ping", resolve));
+
+ browser.test.log("Remove options tab.");
+ await browser.tabs.remove(optionsTab.id);
+
+ browser.test.log("Open options page again. Expect fresh load.");
+ [, tab] = await Promise.all([
+ browser.runtime.openOptionsPage(),
+ awaitOptions(),
+ ]);
+ browser.test.assertEq(optionsURL, tab.url, "Tab contains options.html");
+ browser.test.assertTrue(tab.active, "Tab is active");
+ browser.test.assertTrue(tab.id != optionsTab.id, "Tab is a new tab");
+
+ await browser.tabs.remove(tab.id);
+
+ browser.test.notifyPass("options-ui-tab");
+ } catch (error) {
+ browser.test.fail(`Error: ${error} :: ${error.stack}`);
+ browser.test.notifyFail("options-ui-tab");
+ }
+ },
+ });
+
+ await extension.awaitFinish("options-ui-tab");
+ await extension.unload();
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_options_no_manifest() {
+ info(`Test with no manifest key`);
+
+ let extension = await loadExtension({
+ manifest: {
+ browser_specific_settings: {
+ gecko: { id: "no_options@tests.mozilla.org" },
+ },
+ },
+
+ async background() {
+ browser.test.log(
+ "Try to open options page when not specified in the manifest."
+ );
+
+ await browser.test.assertRejects(
+ browser.runtime.openOptionsPage(),
+ /No `options_ui` declared/,
+ "Expected error from openOptionsPage()"
+ );
+
+ browser.test.notifyPass("options-no-manifest");
+ },
+ });
+
+ await extension.awaitFinish("options-no-manifest");
+ await extension.unload();
+});