summaryrefslogtreecommitdiffstats
path: root/mobile/android/components/extensions/test/mochitest/test_ext_options_ui.html
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/components/extensions/test/mochitest/test_ext_options_ui.html')
-rw-r--r--mobile/android/components/extensions/test/mochitest/test_ext_options_ui.html498
1 files changed, 498 insertions, 0 deletions
diff --git a/mobile/android/components/extensions/test/mochitest/test_ext_options_ui.html b/mobile/android/components/extensions/test/mochitest/test_ext_options_ui.html
new file mode 100644
index 0000000000..138bb054a9
--- /dev/null
+++ b/mobile/android/components/extensions/test/mochitest/test_ext_options_ui.html
@@ -0,0 +1,498 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>PageAction Test</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.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";
+
+async function waitAboutAddonsRendered(addonId) {
+ await ContentTaskUtils.waitForCondition(() => {
+ return content.document.querySelector(`div.addon-item[addonID="${addonId}"]`);
+ }, `wait Addon Item for ${addonId} to be rendered`);
+}
+
+async function navigateToAddonDetails(addonId) {
+ const item = content.document.querySelector(`div.addon-item[addonID="${addonId}"]`);
+ const rect = item.getBoundingClientRect();
+ const x = rect.left + rect.width / 2;
+ const y = rect.top + rect.height / 2;
+ const domWinUtils = content.window.windowUtils;
+
+ domWinUtils.sendMouseEventToWindow("mousedown", x, y, 0, 1, 0);
+ domWinUtils.sendMouseEventToWindow("mouseup", x, y, 0, 1, 0);
+}
+
+async function waitAddonOptionsPage([addonId, expectedText]) {
+ await ContentTaskUtils.waitForCondition(() => {
+ const optionsIframe = content.document.querySelector(`#addon-options`);
+ return optionsIframe && optionsIframe.contentDocument.readyState === "complete" &&
+ optionsIframe.contentDocument.body.innerText.includes(expectedText);
+ }, `wait Addon Options ${expectedText} for ${addonId} to be loaded`);
+
+ const optionsIframe = content.document.querySelector(`#addon-options`);
+
+ return {
+ iframeHeight: optionsIframe.style.height,
+ documentHeight: optionsIframe.contentDocument.documentElement.scrollHeight,
+ bodyHeight: optionsIframe.contentDocument.body.scrollHeight,
+ };
+}
+
+async function clickOnLinkInOptionsPage(selector) {
+ const optionsIframe = content.document.querySelector(`#addon-options`);
+ optionsIframe.contentDocument.querySelector(selector).click();
+}
+
+async function clickAddonOptionButton() {
+ content.document.querySelector(`button#open-addon-options`).click();
+}
+
+async function navigateBack() {
+ content.window.history.back();
+}
+
+function waitDOMContentLoaded(checkUrlCb) {
+ const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
+
+ return new Promise(resolve => {
+ const listener = (event) => {
+ if (checkUrlCb(event.target.defaultView.location.href)) {
+ BrowserApp.deck.removeEventListener("DOMContentLoaded", listener);
+ resolve();
+ }
+ };
+
+ BrowserApp.deck.addEventListener("DOMContentLoaded", listener);
+ });
+}
+
+function waitAboutAddonsLoaded() {
+ return waitDOMContentLoaded(url => url === "about:addons");
+}
+
+function clickAddonDisable() {
+ content.document.querySelector("#disable-btn").click();
+}
+
+function clickAddonEnable() {
+ content.document.querySelector("#enable-btn").click();
+}
+
+add_task(async function test_options_ui_iframe_height() {
+ const addonID = "test-options-ui@mozilla.org";
+
+ const extension = ExtensionTestUtils.loadExtension({
+ useAddonManager: "temporary",
+ manifest: {
+ browser_specific_settings: {
+ gecko: {id: addonID},
+ },
+ name: "Options UI Extension",
+ description: "Longer addon description",
+ options_ui: {
+ page: "options.html",
+ },
+ },
+ files: {
+ // An option page with the document element bigger than the body.
+ "options.html": `<!DOCTYPE html>
+ <html>
+ <head>
+ <meta charset="utf-8">
+ <style>
+ html { height: 500px; border: 1px solid black; }
+ body { height: 200px; }
+ </style>
+ </head>
+ <body>
+ <h1>Options page 1</h1>
+ <a href="options2.html">go to page 2</a>
+ </body>
+ </html>
+ `,
+ // A second option page with the body element bigger than the document.
+ "options2.html": `<!DOCTYPE html>
+ <html>
+ <head>
+ <meta charset="utf-8">
+ <style>
+ html { height: 200px; border: 1px solid black; }
+ body { height: 350px; }
+ </style>
+ </head>
+ <body>
+ <h1>Options page 2</h1>
+ </body>
+ </html>
+ `,
+ },
+ });
+
+ await extension.startup();
+
+ const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
+
+ const onceAboutAddonsLoaded = waitAboutAddonsLoaded();
+
+ BrowserApp.addTab("about:addons", {
+ selected: true,
+ parentId: BrowserApp.selectedTab.id,
+ });
+
+ await onceAboutAddonsLoaded;
+
+ is(BrowserApp.selectedTab.currentURI.spec, "about:addons",
+ "about:addons is the currently selected tab");
+
+ await SpecialPowers.spawn(BrowserApp.selectedTab.browser, [addonID], waitAboutAddonsRendered);
+
+ await SpecialPowers.spawn(BrowserApp.selectedTab.browser, [addonID], navigateToAddonDetails);
+
+ const optionsSizes = await SpecialPowers.spawn(
+ BrowserApp.selectedTab.browser, [[addonID, "Options page 1"]], waitAddonOptionsPage
+ );
+
+ ok(parseInt(optionsSizes.iframeHeight, 10) >= 500,
+ "The addon options iframe is at least 500px");
+
+ is(optionsSizes.iframeHeight, optionsSizes.documentHeight + "px",
+ "The addon options iframe has the expected height");
+
+ await SpecialPowers.spawn(BrowserApp.selectedTab.browser, ["a"], clickOnLinkInOptionsPage);
+
+ const options2Sizes = await SpecialPowers.spawn(
+ BrowserApp.selectedTab.browser, [[addonID, "Options page 2"]], waitAddonOptionsPage
+ );
+
+ // The second option page has a body bigger than the document element
+ // and we expect the iframe to be bigger than that.
+ ok(parseInt(options2Sizes.iframeHeight, 10) > 200,
+ `The iframe is bigger then 200px (${options2Sizes.iframeHeight})`);
+
+ // The second option page has a body smaller than the document element of the first
+ // page and we expect the iframe to be smaller than for the previous options page.
+ ok(parseInt(options2Sizes.iframeHeight, 10) < 500,
+ `The iframe is smaller then 500px (${options2Sizes.iframeHeight})`);
+
+ is(options2Sizes.iframeHeight, options2Sizes.documentHeight + "px",
+ "The second addon options page has the expected height");
+
+ await SpecialPowers.spawn(BrowserApp.selectedTab.browser, [], navigateBack);
+
+ const backToOptionsSizes = await SpecialPowers.spawn(
+ BrowserApp.selectedTab.browser, [[addonID, "Options page 1"]], waitAddonOptionsPage
+ );
+
+ // After going back to the first options page,
+ // we expect the iframe to have the same size of the previous load.
+ is(backToOptionsSizes.iframeHeight, optionsSizes.iframeHeight,
+ `When navigating back, the old iframe size is restored (${backToOptionsSizes.iframeHeight})`);
+
+ BrowserApp.closeTab(BrowserApp.selectedTab);
+
+ await extension.unload();
+});
+
+add_task(async function test_options_ui_open_aboutaddons_details() {
+ const addonID = "test-options-ui-open-addon-details@mozilla.org";
+
+ function background() {
+ browser.test.onMessage.addListener(msg => {
+ if (msg !== "runtime.openOptionsPage") {
+ browser.test.fail(`Received unexpected test message: ${msg}`);
+ return;
+ }
+
+ browser.runtime.openOptionsPage();
+ });
+ }
+
+ function optionsScript() {
+ browser.test.sendMessage("options-page-loaded", window.location.href);
+ }
+
+ const extension = ExtensionTestUtils.loadExtension({
+ useAddonManager: "temporary",
+ background,
+ manifest: {
+ browser_specific_settings: {
+ gecko: {id: addonID},
+ },
+ name: "Options UI open addon details Extension",
+ description: "Longer addon description",
+ options_ui: {
+ page: "options.html",
+ },
+ },
+ files: {
+ "options.js": optionsScript,
+ "options.html": `<!DOCTYPE html>
+ <html>
+ <head>
+ <meta charset="utf-8">
+ </head>
+ <body>
+ <h1>Options page</h1>
+ <script src="options.js"><\/script>
+ </body>
+ </html>
+ `,
+ },
+ });
+
+ await extension.startup();
+
+ const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
+
+ const onceAboutAddonsLoaded = waitAboutAddonsLoaded();
+
+ BrowserApp.addTab("about:addons", {
+ selected: true,
+ parentId: BrowserApp.selectedTab.id,
+ });
+
+ await onceAboutAddonsLoaded;
+
+ is(BrowserApp.selectedTab.currentURI.spec, "about:addons",
+ "about:addons is the currently selected tab");
+
+ info("Wait runtime.openOptionsPage to open the about:addond details in the existent tab");
+ extension.sendMessage("runtime.openOptionsPage");
+ await extension.awaitMessage("options-page-loaded");
+
+ is(BrowserApp.selectedTab.currentURI.spec, "about:addons",
+ "about:addons is still the currently selected tab once the options has been loaded");
+
+ BrowserApp.closeTab(BrowserApp.selectedTab);
+
+ await extension.unload();
+});
+
+add_task(async function test_options_ui_open_in_tab() {
+ const addonID = "test-options-ui@mozilla.org";
+
+ function background() {
+ browser.test.onMessage.addListener(msg => {
+ if (msg !== "runtime.openOptionsPage") {
+ browser.test.fail(`Received unexpected test message: ${msg}`);
+ return;
+ }
+
+ browser.runtime.openOptionsPage();
+ });
+ }
+
+ function optionsScript() {
+ browser.test.sendMessage("options-page-loaded", window.location.href);
+ }
+
+ const extension = ExtensionTestUtils.loadExtension({
+ useAddonManager: "temporary",
+ background,
+ manifest: {
+ browser_specific_settings: {
+ gecko: {id: addonID},
+ },
+ name: "Options UI open_in_tab Extension",
+ description: "Longer addon description",
+ options_ui: {
+ page: "options.html",
+ open_in_tab: true,
+ },
+ },
+ files: {
+ "options.js": optionsScript,
+ "options.html": `<!DOCTYPE html>
+ <html>
+ <head>
+ <meta charset="utf-8">
+ </head>
+ <body>
+ <h1>Options page</h1>
+ <script src="options.js"><\/script>
+ </body>
+ </html>
+ `,
+ },
+ });
+
+ await extension.startup();
+
+ const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
+
+ const onceAboutAddonsLoaded = waitAboutAddonsLoaded();
+
+ BrowserApp.selectOrAddTab("about:addons", {
+ selected: true,
+ parentId: BrowserApp.selectedTab.id,
+ });
+
+ await onceAboutAddonsLoaded;
+
+ const aboutAddonsTab = BrowserApp.selectedTab;
+
+ is(aboutAddonsTab.currentURI.spec, "about:addons",
+ "about:addons is the currently selected tab");
+
+ await SpecialPowers.spawn(aboutAddonsTab.browser, [addonID], waitAboutAddonsRendered);
+ await SpecialPowers.spawn(aboutAddonsTab.browser, [addonID], navigateToAddonDetails);
+
+ const onceAddonOptionsLoaded = waitDOMContentLoaded(url => url.endsWith("options.html"));
+
+ info("Click the Options button in the addon details");
+ await SpecialPowers.spawn(aboutAddonsTab.browser, [], clickAddonOptionButton);
+
+ info("Waiting that the addon options are loaded in a new tab");
+ await onceAddonOptionsLoaded;
+
+ const addonOptionsTab = BrowserApp.selectedTab;
+
+ ok(aboutAddonsTab.id !== addonOptionsTab.id,
+ "The Addon Options page has been loaded in a new tab");
+
+ let optionsURL = await extension.awaitMessage("options-page-loaded");
+
+ is(addonOptionsTab.currentURI.spec, optionsURL,
+ "Got the expected extension url opened in the addon options tab");
+
+ const waitTabClosed = (nativeTab) => {
+ return new Promise(resolve => {
+ const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
+ const expectedBrowser = nativeTab.browser;
+
+ const tabCloseListener = (event) => {
+ const browser = event.target;
+ if (browser !== expectedBrowser) {
+ return;
+ }
+
+ BrowserApp.deck.removeEventListener("TabClose", tabCloseListener);
+ resolve();
+ };
+
+ BrowserApp.deck.addEventListener("TabClose", tabCloseListener);
+ });
+ };
+
+ const onceOptionsTabClosed = waitTabClosed(addonOptionsTab);
+ const onceAboutAddonsClosed = waitTabClosed(aboutAddonsTab);
+
+ info("Close the opened about:addons and options tab");
+ BrowserApp.closeTab(addonOptionsTab);
+ BrowserApp.closeTab(aboutAddonsTab);
+
+ info("Wait the tabs to be closed");
+ await Promise.all([onceOptionsTabClosed, onceAboutAddonsClosed]);
+
+ const oldSelectedTab = BrowserApp.selectedTab;
+ info("Call runtime.openOptionsPage");
+ extension.sendMessage("runtime.openOptionsPage");
+
+ info("Wait runtime.openOptionsPage to open the options in a new tab");
+ optionsURL = await extension.awaitMessage("options-page-loaded");
+ is(BrowserApp.selectedTab.currentURI.spec, optionsURL,
+ "runtime.openOptionsPage has opened the expected extension page");
+ ok(BrowserApp.selectedTab !== oldSelectedTab,
+ "runtime.openOptionsPage has opened a new tab");
+
+ BrowserApp.closeTab(BrowserApp.selectedTab);
+
+ await extension.unload();
+});
+
+add_task(async function test_options_ui_on_disable_and_enable() {
+ // Temporarily disabled for races.
+ /* eslint-disable no-unreachable */
+ return;
+
+ const addonID = "test-options-ui-disable-enable@mozilla.org";
+
+ function optionsScript() {
+ browser.test.sendMessage("options-page-loaded", window.location.href);
+ }
+
+ const extension = ExtensionTestUtils.loadExtension({
+ useAddonManager: "temporary",
+ manifest: {
+ browser_specific_settings: {
+ gecko: {id: addonID},
+ },
+ name: "Options UI open addon details Extension",
+ description: "Longer addon description",
+ options_ui: {
+ page: "options.html",
+ },
+ },
+ files: {
+ "options.js": optionsScript,
+ "options.html": `<!DOCTYPE html>
+ <html>
+ <head>
+ <meta charset="utf-8">
+ </head>
+ <body>
+ <h1>Options page</h1>
+ <script src="options.js"><\/script>
+ </body>
+ </html>
+ `,
+ },
+ });
+
+ await extension.startup();
+
+ const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
+
+ const onceAboutAddonsLoaded = waitAboutAddonsLoaded();
+
+ BrowserApp.addTab("about:addons", {
+ selected: true,
+ parentId: BrowserApp.selectedTab.id,
+ });
+
+ await onceAboutAddonsLoaded;
+
+ const aboutAddonsTab = BrowserApp.selectedTab;
+
+ is(aboutAddonsTab.currentURI.spec, "about:addons",
+ "about:addons is the currently selected tab");
+
+ info("Wait the addon details to have been loaded");
+ await SpecialPowers.spawn(aboutAddonsTab.browser, [addonID], waitAboutAddonsRendered);
+ await SpecialPowers.spawn(aboutAddonsTab.browser, [addonID], navigateToAddonDetails);
+
+ info("Wait the addon options page to have been loaded");
+ await extension.awaitMessage("options-page-loaded");
+
+ info("Click the addon disable button");
+ await SpecialPowers.spawn(aboutAddonsTab.browser, [], clickAddonDisable);
+
+ // NOTE: Currently after disabling the addon the extension.awaitMessage seems
+ // to fail be able to receive events coming from the browser.test.sendMessage API
+ // (nevertheless `await extension.unload()` seems to be able to remove the extension),
+ // falling back to wait for the options page to be loaded here.
+ const onceAddonOptionsLoaded = waitDOMContentLoaded(url => url.endsWith("options.html"));
+
+ info("Click the addon enable button");
+ await SpecialPowers.spawn(aboutAddonsTab.browser, [], clickAddonEnable);
+
+ info("Wait the addon options page to have been loaded after clicking the addon enable button");
+ await onceAddonOptionsLoaded;
+
+ BrowserApp.closeTab(BrowserApp.selectedTab);
+
+ await extension.unload();
+});
+
+</script>
+
+</body>
+</html>