Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>PageAction Test</title>
<script type="text/javascript" src="head.js"></script>
</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>