Bug 1896217 - Deprecate tabs.executeScript(), tabs.insertCSS() and tabs.removeCSS() after Manifest V2 and add tests for the scripting API in Manifest V3. r=aleca

The scripting API was added for Manifest V3. This adds tests for this
new API.

Differential Revision: https://phabricator.services.mozilla.com/D210103

--HG--
rename : mail/components/extensions/test/browser/browser_ext_composeScripts.js => mail/components/extensions/test/browser/browser_ext_composeScripts_mv3.js
rename : mail/components/extensions/test/browser/browser_ext_contentScripts.js => mail/components/extensions/test/browser/browser_ext_contentScripts_mv3.js
rename : mail/components/extensions/test/browser/browser_ext_messageDisplayScripts.js => mail/components/extensions/test/browser/browser_ext_messageDisplayScripts_mv3.js
extra : amend_source : 4eece16a87e9f5e1c61d360d43f9de9cf522429e
This commit is contained in:
John Bieling 2024-05-15 10:27:24 +12:00
Родитель 14b38725b1
Коммит c2efdabd7d
5 изменённых файлов: 1962 добавлений и 0 удалений

Просмотреть файл

@ -715,6 +715,7 @@
{
"name": "executeScript",
"type": "function",
"max_manifest_version": 2,
"description": "Injects JavaScript code into a page. For details, see the `programmatic injection <|link-content-scripts|>`__ section of the content scripts doc.",
"async": "callback",
"parameters": [
@ -752,6 +753,7 @@
{
"name": "insertCSS",
"type": "function",
"max_manifest_version": 2,
"description": "Injects CSS into a page. For details, see the `programmatic injection <|link-content-scripts|>`__ section of the content scripts doc.",
"async": "callback",
"parameters": [
@ -779,6 +781,7 @@
{
"name": "removeCSS",
"type": "function",
"max_manifest_version": 2,
"description": "Removes injected CSS from a page. For details, see the `programmatic injection <|link-content-scripts|>`__ section of the content scripts doc.",
"async": "callback",
"parameters": [

Просмотреть файл

@ -67,11 +67,13 @@ support-files = data/cloudFile1.txt data/cloudFile2.txt
[browser_ext_composeAction_popup_click_mv3_event_pages.js]
[browser_ext_composeAction_properties.js]
[browser_ext_composeScripts.js]
[browser_ext_composeScripts_mv3.js]
[browser_ext_content_handler.js]
[browser_ext_content_tabs_navigation_menu.js]
support-files = data/content.html
tags = contextmenu
[browser_ext_contentScripts.js]
[browser_ext_contentScripts_mv3.js]
[browser_ext_mailTabs_create.js]
[browser_ext_mailTabs_folderModes.js]
[browser_ext_mailTabs_getListedMessages.js]
@ -124,6 +126,7 @@ support-files = messages/attachedMessageSample.eml
[browser_ext_messageDisplayAction_popup_click_mv3_event_pages.js]
[browser_ext_messageDisplayAction_properties.js]
[browser_ext_messageDisplayScripts.js]
[browser_ext_messageDisplayScripts_mv3.js]
[browser_ext_messages_open_attachment.js]
[browser_ext_quickFilter.js]
[browser_ext_runtime_getContexts.js]

Просмотреть файл

@ -0,0 +1,554 @@
/* 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/. */
addIdentity(createAccount());
async function checkComposeBody(expected, waitForEvent) {
const composeWindows = [...Services.wm.getEnumerator("msgcompose")];
Assert.equal(composeWindows.length, 1);
const composeWindow = composeWindows[0];
if (waitForEvent) {
await BrowserTestUtils.waitForEvent(
composeWindow,
"extension-scripts-added"
);
}
const composeEditor = composeWindow.GetCurrentEditorElement();
await checkContent(composeEditor, expected);
}
/** Tests browser.scripting.insertCSS and browser.scripting.removeCSS. */
add_task(async function testInsertRemoveCSSViaScriptingAPI() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const tab = await browser.compose.beginNew();
await window.sendMessage();
await browser.scripting.insertCSS({
target: { tabId: tab.id },
css: "body { background-color: lime; }",
});
await window.sendMessage();
await browser.scripting.removeCSS({
target: { tabId: tab.id },
css: "body { background-color: lime; }",
});
await window.sendMessage();
await browser.scripting.insertCSS({
target: { tabId: tab.id },
files: ["test.css"],
});
await window.sendMessage();
await browser.scripting.removeCSS({
target: { tabId: tab.id },
files: ["test.css"],
});
await window.sendMessage();
await browser.tabs.remove(tab.id);
browser.test.notifyPass("finished");
},
"test.css": "body { background-color: green; }",
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["compose", "scripting"],
},
});
await extension.startup();
await extension.awaitMessage();
await checkComposeBody({ backgroundColor: "rgba(0, 0, 0, 0)" });
extension.sendMessage();
await extension.awaitMessage();
await checkComposeBody({ backgroundColor: "rgb(0, 255, 0)" });
extension.sendMessage();
await extension.awaitMessage();
await checkComposeBody({ backgroundColor: "rgba(0, 0, 0, 0)" });
extension.sendMessage();
await extension.awaitMessage();
await checkComposeBody({ backgroundColor: "rgb(0, 128, 0)" });
extension.sendMessage();
await extension.awaitMessage();
await checkComposeBody({ backgroundColor: "rgba(0, 0, 0, 0)" });
extension.sendMessage();
await extension.awaitFinish("finished");
await extension.unload();
});
/** Tests browser.scripting.insertCSS fails without the "compose" permission. */
add_task(async function testInsertRemoveCSSNoPermissions() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const tab = await browser.compose.beginNew();
await browser.test.assertRejects(
browser.scripting.insertCSS({
target: { tabId: tab.id },
css: "body { background-color: darkred; }",
}),
/Missing host permission for the tab/,
"insertCSS without permission should throw"
);
await browser.test.assertRejects(
browser.scripting.insertCSS({
target: { tabId: tab.id },
files: ["test.css"],
}),
/Missing host permission for the tab/,
"insertCSS without permission should throw"
);
await window.sendMessage();
await browser.tabs.remove(tab.id);
browser.test.notifyPass("finished");
},
"test.css": "body { background-color: red; }",
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["scripting"],
},
});
await extension.startup();
await extension.awaitMessage();
await checkComposeBody({
backgroundColor: "rgba(0, 0, 0, 0)",
textContent: "",
});
extension.sendMessage();
await extension.awaitFinish("finished");
await extension.unload();
});
/** Tests browser.scripting.executeScript. */
add_task(async function testExecuteScript() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const tab = await browser.compose.beginNew();
await window.sendMessage();
await browser.scripting.executeScript({
target: { tabId: tab.id },
func: () => {
document.body.setAttribute("foo", "bar");
},
});
await window.sendMessage();
await browser.scripting.executeScript({
target: { tabId: tab.id },
files: ["test.js"],
});
await window.sendMessage();
await browser.tabs.remove(tab.id);
browser.test.notifyPass("finished");
},
"test.js": () => {
document.body.textContent = "Hey look, the script ran!";
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["compose", "scripting"],
},
});
await extension.startup();
await extension.awaitMessage();
await checkComposeBody({ textContent: "" });
extension.sendMessage();
await extension.awaitMessage();
await checkComposeBody({ foo: "bar" });
extension.sendMessage();
await extension.awaitMessage();
await checkComposeBody({
foo: "bar",
textContent: "Hey look, the script ran!",
});
extension.sendMessage();
await extension.awaitFinish("finished");
await extension.unload();
});
/** Tests browser.scripting.executeScript fails without the "compose" permission. */
add_task(async function testExecuteScriptNoPermissions() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const tab = await browser.compose.beginNew();
await browser.test.assertRejects(
browser.scripting.executeScript({
target: { tabId: tab.id },
func: () => {
document.body.setAttribute("foo", "bar");
},
}),
/Missing host permission for the tab/,
"executeScript without permission should throw"
);
await browser.test.assertRejects(
browser.scripting.executeScript({
target: { tabId: tab.id },
files: ["test.js"],
}),
/Missing host permission for the tab/,
"executeScript without permission should throw"
);
await window.sendMessage();
await browser.tabs.remove(tab.id);
browser.test.notifyPass("finished");
},
"test.js": () => {
document.body.textContent = "Hey look, the script ran!";
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["scripting"],
},
});
await extension.startup();
await extension.awaitMessage();
await checkComposeBody({ foo: null, textContent: "" });
extension.sendMessage();
await extension.awaitFinish("finished");
await extension.unload();
});
/** Tests the messenger alias is available. */
add_task(async function testExecuteScriptAlias() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const tab = await browser.compose.beginNew();
await window.sendMessage();
await browser.scripting.executeScript({
target: { tabId: tab.id },
func: () => {
// eslint-disable-next-line no-undef
const id = messenger.runtime.getManifest().applications.gecko.id;
document.body.textContent = id;
},
});
await window.sendMessage();
await browser.tabs.remove(tab.id);
browser.test.notifyPass("finished");
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
browser_specific_settings: { gecko: { id: "compose_scripts@mochitest" } },
background: { scripts: ["utils.js", "background.js"] },
permissions: ["compose", "scripting"],
},
});
await extension.startup();
await extension.awaitMessage();
await checkComposeBody({ textContent: "" });
extension.sendMessage();
await extension.awaitMessage();
await checkComposeBody({ textContent: "compose_scripts@mochitest" });
extension.sendMessage();
await extension.awaitFinish("finished");
await extension.unload();
});
/**
* Tests browser.composeScripts.register correctly adds CSS and JavaScript to
* message composition windows opened after it was called. Also tests calling
* `unregister` on the returned object.
*/
add_task(async function testRegisterBeforeCompose() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const registeredScript = await browser.composeScripts.register({
css: [{ code: "body { color: white }" }, { file: "test.css" }],
js: [
{ code: `document.body.setAttribute("foo", "bar");` },
{ file: "test.js" },
],
});
await browser.compose.beginNew();
await window.sendMessage();
await registeredScript.unregister();
browser.test.notifyPass("finished");
},
"test.css": "body { background-color: green; }",
"test.js": () => {
document.body.textContent = "Hey look, the script ran!";
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["compose"],
},
});
await extension.startup();
await extension.awaitMessage();
await checkComposeBody(
{
backgroundColor: "rgb(0, 128, 0)",
color: "rgb(255, 255, 255)",
foo: "bar",
textContent: "Hey look, the script ran!",
},
true
);
extension.sendMessage();
await extension.awaitFinish("finished");
await checkComposeBody({
backgroundColor: "rgb(0, 128, 0)",
color: "rgb(255, 255, 255)",
foo: "bar",
textContent: "Hey look, the script ran!",
});
await extension.unload();
await checkComposeBody({
backgroundColor: "rgba(0, 0, 0, 0)",
color: "rgb(0, 0, 0)",
foo: "bar",
textContent: "Hey look, the script ran!",
});
await BrowserTestUtils.closeWindow(
Services.wm.getMostRecentWindow("msgcompose")
);
});
/**
* Tests browser.composeScripts.register correctly adds CSS and JavaScript to
* message composition windows already open when it was called. Also tests
* calling `unregister` on the returned object.
*/
add_task(async function testRegisterDuringCompose() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const tab = await browser.compose.beginNew();
await window.sendMessage();
const registeredScript = await browser.composeScripts.register({
css: [{ code: "body { color: white }" }, { file: "test.css" }],
js: [
{ code: `document.body.setAttribute("foo", "bar");` },
{ file: "test.js" },
],
});
await window.sendMessage();
await registeredScript.unregister();
await window.sendMessage();
await browser.tabs.remove(tab.id);
browser.test.notifyPass("finished");
},
"test.css": "body { background-color: green; }",
"test.js": () => {
document.body.textContent = "Hey look, the script ran!";
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["compose"],
},
});
await extension.startup();
await extension.awaitMessage();
await checkComposeBody({
backgroundColor: "rgba(0, 0, 0, 0)",
textContent: "",
});
extension.sendMessage();
await extension.awaitMessage();
await checkComposeBody({
backgroundColor: "rgba(0, 0, 0, 0)",
textContent: "",
});
extension.sendMessage();
await extension.awaitMessage();
await checkComposeBody({
backgroundColor: "rgba(0, 0, 0, 0)",
textContent: "",
});
extension.sendMessage();
await extension.awaitFinish("finished");
await extension.unload();
});
/** Tests content_scripts in the manifest do not affect compose windows. */
async function subtestContentScriptManifest(permissions) {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const tab = await browser.compose.beginNew();
await window.sendMessage();
await browser.tabs.remove(tab.id);
browser.test.notifyPass("finished");
},
"test.css": "body { background-color: red; }",
"test.js": () => {
document.body.textContent = "Hey look, the script ran!";
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions,
content_scripts: [
{
matches: ["<all_urls>"],
css: ["test.css"],
js: ["test.js"],
match_about_blank: true,
match_origin_as_fallback: true,
},
],
},
});
// match_origin_as_fallback is not implemented yet. Bug 1475831.
ExtensionTestUtils.failOnSchemaWarnings(false);
await extension.startup();
ExtensionTestUtils.failOnSchemaWarnings(true);
await extension.awaitMessage();
await checkComposeBody({
backgroundColor: "rgba(0, 0, 0, 0)",
textContent: "",
});
extension.sendMessage();
await extension.awaitFinish("finished");
await extension.unload();
}
add_task(async function testContentScriptManifestNoPermission() {
await subtestContentScriptManifest([]);
});
add_task(async function testContentScriptManifest() {
await subtestContentScriptManifest(["compose"]);
});
/** Tests registered content scripts do not affect compose windows. */
async function subtestContentScriptRegister(permissions) {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
await browser.scripting.registerContentScripts([
{
id: "test",
matches: ["<all_urls>"],
css: ["test.css"],
js: ["test.js"],
},
]);
const tab = await browser.compose.beginNew();
await window.sendMessage();
await browser.tabs.remove(tab.id);
browser.test.notifyPass("finished");
},
"test.css": "body { background-color: red; }",
"test.js": () => {
document.body.textContent = "Hey look, the script ran!";
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions,
host_permissions: ["<all_urls>"],
},
});
await extension.startup();
await extension.awaitMessage();
await checkComposeBody({
backgroundColor: "rgba(0, 0, 0, 0)",
textContent: "",
});
extension.sendMessage();
await extension.awaitFinish("finished");
await extension.unload();
}
add_task(async function testContentScriptRegisterNoPermission() {
await subtestContentScriptRegister(["scripting"]);
});
add_task(async function testContentScriptRegister() {
await subtestContentScriptRegister(["scripting", "compose"]);
});

Просмотреть файл

@ -0,0 +1,482 @@
/* 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/. */
const CONTENT_PAGE =
"http://mochi.test:8888/browser/comm/mail/components/extensions/test/browser/data/content.html";
const UNCHANGED_VALUES = {
backgroundColor: "rgba(0, 0, 0, 0)",
color: "rgb(0, 0, 0)",
foo: null,
textContent: "\n This is text.\n This is a link with text.\n \n\n\n",
};
/** Tests browser.scripting.insertCSS and browser.scripting.removeCSS. */
add_task(async function testInsertRemoveCSS() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const [tab] = await browser.tabs.query({ active: true });
await browser.scripting.insertCSS({
target: { tabId: tab.id },
css: "body { background-color: lime; }",
});
await window.sendMessage();
await browser.scripting.removeCSS({
target: { tabId: tab.id },
css: "body { background-color: lime; }",
});
await window.sendMessage();
await browser.scripting.insertCSS({
target: { tabId: tab.id },
files: ["test.css"],
});
await window.sendMessage();
await browser.scripting.removeCSS({
target: { tabId: tab.id },
files: ["test.css"],
});
browser.test.notifyPass("finished");
},
"test.css": "body { background-color: green; }",
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["scripting"],
host_permissions: ["*://mochi.test/*"],
},
});
const tab = window.openContentTab(CONTENT_PAGE);
await awaitBrowserLoaded(tab.browser, CONTENT_PAGE);
await extension.startup();
await extension.awaitMessage(); // insertCSS with code
await checkContent(tab.browser, { backgroundColor: "rgb(0, 255, 0)" });
extension.sendMessage();
await extension.awaitMessage(); // removeCSS with code
await checkContent(tab.browser, UNCHANGED_VALUES);
extension.sendMessage();
await extension.awaitMessage(); // insertCSS with file
await checkContent(tab.browser, { backgroundColor: "rgb(0, 128, 0)" });
extension.sendMessage();
await extension.awaitFinish("finished"); // removeCSS with file
await checkContent(tab.browser, UNCHANGED_VALUES);
await extension.unload();
document.getElementById("tabmail").closeTab(tab);
});
/** Tests browser.scripting.insertCSS fails without the host permission. */
add_task(async function testInsertRemoveCSSNoHostPermissions() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const [tab] = await browser.tabs.query({ active: true });
await browser.test.assertRejects(
browser.scripting.insertCSS({
target: { tabId: tab.id },
css: "body { background-color: darkred; }",
}),
/Missing host permission for the tab/,
"insertCSS without permission should throw"
);
await browser.test.assertRejects(
browser.scripting.insertCSS({
target: { tabId: tab.id },
files: ["test.css"],
}),
/Missing host permission for the tab/,
"insertCSS without permission should throw"
);
await browser.test.assertRejects(
browser.scripting.insertCSS({
target: { tabId: tab.id },
files: ["test.css"],
}),
/Missing host permission for the tab/,
"insertCSS without permission should throw"
);
browser.test.notifyPass("finished");
},
"test.css": "body { background-color: red; }",
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["scripting"],
},
});
const tab = window.openContentTab(CONTENT_PAGE);
await awaitBrowserLoaded(tab.browser, CONTENT_PAGE);
await extension.startup();
await extension.awaitFinish("finished");
await checkContent(tab.browser, UNCHANGED_VALUES);
await extension.unload();
document.getElementById("tabmail").closeTab(tab);
});
/** Tests browser.scripting.executeScript. */
add_task(async function testExecuteScript() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const [tab] = await browser.tabs.query({ active: true });
await browser.scripting.executeScript({
target: { tabId: tab.id },
func: () => {
document.body.setAttribute("foo", "bar");
},
});
await window.sendMessage();
await browser.scripting.executeScript({
target: { tabId: tab.id },
files: ["test.js"],
});
browser.test.notifyPass("finished");
},
"test.js": () => {
document.body.textContent = "Hey look, the script ran!";
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["scripting"],
host_permissions: ["*://mochi.test/*"],
},
});
const tab = window.openContentTab(CONTENT_PAGE);
await awaitBrowserLoaded(tab.browser, CONTENT_PAGE);
await extension.startup();
await extension.awaitMessage(); // executeScript with code
await checkContent(tab.browser, { foo: "bar" });
extension.sendMessage();
await extension.awaitFinish("finished"); // executeScript with file
await checkContent(tab.browser, {
foo: "bar",
textContent: "Hey look, the script ran!",
});
await extension.unload();
document.getElementById("tabmail").closeTab(tab);
});
/** Tests browser.scripting.executeScript fails without the host permission. */
add_task(async function testExecuteScriptNoHostPermissions() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const [tab] = await browser.tabs.query({ active: true });
await browser.test.assertRejects(
browser.scripting.executeScript({
target: { tabId: tab.id },
func: () => {
document.body.setAttribute("foo", "bar");
},
}),
/Missing host permission for the tab/,
"executeScript without permission should throw"
);
await browser.test.assertRejects(
browser.scripting.executeScript({
target: { tabId: tab.id },
files: ["test.js"],
}),
/Missing host permission for the tab/,
"executeScript without permission should throw"
);
await browser.test.assertRejects(
browser.scripting.executeScript({
target: { tabId: tab.id },
files: ["test.js"],
}),
/Missing host permission for the tab/,
"executeScript without permission should throw"
);
browser.test.notifyPass("finished");
},
"test.js": () => {
document.body.textContent = "Hey look, the script ran!";
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["scripting"],
},
});
const tab = window.openContentTab(CONTENT_PAGE);
await awaitBrowserLoaded(tab.browser, CONTENT_PAGE);
await extension.startup();
await extension.awaitFinish("finished");
await checkContent(tab.browser, UNCHANGED_VALUES);
await extension.unload();
document.getElementById("tabmail").closeTab(tab);
});
/** Tests the messenger alias is available. */
add_task(async function testExecuteScriptAlias() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const [tab] = await browser.tabs.query({ active: true });
await browser.scripting.executeScript({
target: { tabId: tab.id },
func: () => {
// eslint-disable-next-line no-undef
const id = messenger.runtime.getManifest().applications.gecko.id;
document.body.textContent = id;
},
});
browser.test.notifyPass("finished");
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
browser_specific_settings: { gecko: { id: "content_scripts@mochitest" } },
background: { scripts: ["utils.js", "background.js"] },
permissions: ["scripting"],
host_permissions: ["*://mochi.test/*"],
},
});
const tab = window.openContentTab(CONTENT_PAGE);
await awaitBrowserLoaded(tab.browser, CONTENT_PAGE);
await extension.startup();
await extension.awaitFinish("finished");
await checkContent(tab.browser, { textContent: "content_scripts@mochitest" });
await extension.unload();
document.getElementById("tabmail").closeTab(tab);
});
/**
* Tests browser.contentScripts.register correctly adds CSS and JavaScript to
* message composition windows opened after it was called. Also tests calling
* `unregister` on the returned object.
*/
add_task(async function testRegister() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
await browser.scripting.registerContentScripts([
{
id: "test",
css: ["test.css"],
js: ["test.js"],
matches: ["*://mochi.test/*"],
},
]);
await window.sendMessage();
await browser.scripting.unregisterContentScripts();
await window.sendMessage();
browser.test.notifyPass("finished");
},
"test.css": "body { color: white; background-color: green; }",
"test.js": () => {
document.body.setAttribute("foo", "bar");
document.body.textContent = "Hey look, the script ran!";
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["scripting"],
host_permissions: ["*://mochi.test/*"],
},
});
// Tab 1: loads before the script is registered.
const tab1 = window.openContentTab(CONTENT_PAGE + "?tab1");
await awaitBrowserLoaded(tab1.browser, CONTENT_PAGE + "?tab1");
await extension.startup();
await extension.awaitMessage(); // register
// Registering a script will not inject it into already open tabs, wait a moment
// to make sure we still get the unchanged values.
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(r => setTimeout(r, 1000));
await checkContent(tab1.browser, UNCHANGED_VALUES);
// Tab 2: loads after the script is registered.
const tab2 = window.openContentTab(CONTENT_PAGE + "?tab2");
await awaitBrowserLoaded(tab2.browser, CONTENT_PAGE + "?tab2");
await checkContent(tab2.browser, {
backgroundColor: "rgb(0, 128, 0)",
color: "rgb(255, 255, 255)",
foo: "bar",
textContent: "Hey look, the script ran!",
});
extension.sendMessage();
await extension.awaitMessage(); // unregister
await checkContent(tab2.browser, {
backgroundColor: "rgb(0, 128, 0)",
color: "rgb(255, 255, 255)",
foo: "bar",
textContent: "Hey look, the script ran!",
});
// Tab 3: loads after the script is unregistered.
const tab3 = window.openContentTab(CONTENT_PAGE + "?tab3");
await awaitBrowserLoaded(tab3.browser, CONTENT_PAGE + "?tab3");
await checkContent(tab3.browser, UNCHANGED_VALUES);
extension.sendMessage();
await extension.awaitFinish("finished");
await extension.unload();
// Tab 2 should have the CSS removed.
await checkContent(tab2.browser, {
backgroundColor: UNCHANGED_VALUES.backgroundColor,
color: UNCHANGED_VALUES.color,
foo: "bar",
textContent: "Hey look, the script ran!",
});
const tabmail = document.getElementById("tabmail");
tabmail.closeOtherTabs(tabmail.tabInfo[0]);
});
/** Tests content_scripts in the manifest with permission work. */
add_task(async function testManifest() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"test.css": "body { background-color: lime; }",
"test.js": () => {
document.body.textContent = "Hey look, the script ran!";
},
},
manifest: {
manifest_version: 3,
content_scripts: [
{
matches: ["<all_urls>"],
css: ["test.css"],
js: ["test.js"],
},
],
},
});
// Tab 1: loads before the script is registered.
const tab1 = window.openContentTab(CONTENT_PAGE + "?tab1");
await awaitBrowserLoaded(tab1.browser, CONTENT_PAGE + "?tab1");
// The extension is not running, no script should be injected, wait a moment to
// make sure we still get the unchanged values.
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(r => setTimeout(r, 1000));
await checkContent(tab1.browser, UNCHANGED_VALUES);
await extension.startup();
// The extension started and the content script defined in the manifest should
// be injected into the already open tab.
await checkContent(tab1.browser, {
backgroundColor: "rgb(0, 255, 0)",
textContent: "Hey look, the script ran!",
});
// Tab 2: loads after the script is registered.
const tab2 = window.openContentTab(CONTENT_PAGE + "?tab2");
await awaitBrowserLoaded(tab2.browser, CONTENT_PAGE + "?tab2");
await checkContent(tab2.browser, {
backgroundColor: "rgb(0, 255, 0)",
textContent: "Hey look, the script ran!",
});
await extension.unload();
// Tab 2 should have the CSS removed.
await checkContent(tab2.browser, {
backgroundColor: UNCHANGED_VALUES.backgroundColor,
textContent: "Hey look, the script ran!",
});
const tabmail = document.getElementById("tabmail");
tabmail.closeOtherTabs(tabmail.tabInfo[0]);
});
/** Tests content_scripts match patterns in the manifest. */
add_task(async function testManifestNoPermissions() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"test.css": "body { background-color: red; }",
"test.js": () => {
document.body.textContent = "Hey look, the script ran!";
},
},
manifest: {
manifest_version: 3,
content_scripts: [
{
matches: ["*://example.org/*"],
css: ["test.css"],
js: ["test.js"],
},
],
},
});
await extension.startup();
const tab = window.openContentTab(CONTENT_PAGE);
await awaitBrowserLoaded(tab.browser, CONTENT_PAGE);
await checkContent(tab.browser, UNCHANGED_VALUES);
await extension.unload();
document.getElementById("tabmail").closeTab(tab);
});

Просмотреть файл

@ -0,0 +1,920 @@
/* 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/. */
let account, messages;
let tabmail, about3Pane, messagePane;
add_setup(async () => {
account = createAccount();
const rootFolder = account.incomingServer.rootFolder;
rootFolder.createSubfolder("messageDisplayScripts", null);
const folder = rootFolder.getChildNamed("messageDisplayScripts");
createMessages(folder, 11);
messages = [...folder.messages];
tabmail = document.getElementById("tabmail");
about3Pane = tabmail.currentTabInfo.chromeBrowser.contentWindow;
about3Pane.displayFolder(folder.URI);
messagePane =
about3Pane.messageBrowser.contentDocument.getElementById("messagepane");
});
async function checkMessageBody(expected, message, browser) {
if (message && "textContent" in expected) {
let body = await new Promise(resolve => {
window.MsgHdrToMimeMessage(message, null, (msgHdr, mimeMessage) => {
resolve(mimeMessage.parts[0].body);
});
});
// Ignore Windows line-endings, they're not important here.
body = body.replace(/\r/g, "");
expected.textContent = body + expected.textContent;
}
if (!browser) {
browser = messagePane;
}
await checkContent(browser, expected);
}
/** Tests browser.scripting.insertCSS and browser.scripting.removeCSS. */
add_task(async function testInsertRemoveCSSViaScriptingAPI() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const [tab] = await browser.tabs.query({ type: ["mail"] });
await window.sendMessage();
await browser.scripting.insertCSS({
target: { tabId: tab.id },
css: "body { background-color: lime; }",
});
await window.sendMessage();
await browser.scripting.removeCSS({
target: { tabId: tab.id },
css: "body { background-color: lime; }",
});
await window.sendMessage();
await browser.scripting.insertCSS({
target: { tabId: tab.id },
files: ["test.css"],
});
await window.sendMessage();
await browser.scripting.removeCSS({
target: { tabId: tab.id },
files: ["test.css"],
});
browser.test.notifyPass("finished");
},
"test.css": "body { background-color: green; }",
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["messagesModify", "scripting"],
},
});
about3Pane.threadTree.selectedIndex = 2;
await awaitBrowserLoaded(messagePane);
await extension.startup();
await extension.awaitMessage();
await checkMessageBody(
{ backgroundColor: "rgba(0, 0, 0, 0)" },
messages.at(-3)
);
extension.sendMessage();
await extension.awaitMessage();
await checkMessageBody(
{ backgroundColor: "rgb(0, 255, 0)" },
messages.at(-3)
);
extension.sendMessage();
await extension.awaitMessage();
await checkMessageBody(
{ backgroundColor: "rgba(0, 0, 0, 0)" },
messages.at(-3)
);
extension.sendMessage();
await extension.awaitMessage();
await checkMessageBody(
{ backgroundColor: "rgb(0, 128, 0)" },
messages.at(-3)
);
extension.sendMessage();
await extension.awaitFinish("finished");
await checkMessageBody(
{ backgroundColor: "rgba(0, 0, 0, 0)" },
messages.at(-3)
);
await extension.unload();
});
/** Tests browser.scripting.insertCSS fails without the "messagesModify" permission. */
add_task(async function testInsertRemoveCSSNoHostPermissions() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const [tab] = await browser.tabs.query({ type: ["mail"] });
await browser.test.assertRejects(
browser.scripting.insertCSS({
target: { tabId: tab.id },
css: "body { background-color: darkred; }",
}),
/Missing host permission for the tab/,
"insertCSS without permission should throw"
);
await browser.test.assertRejects(
browser.scripting.insertCSS({
target: { tabId: tab.id },
files: ["test.css"],
}),
/Missing host permission for the tab/,
"insertCSS without permission should throw"
);
await browser.test.assertRejects(
browser.scripting.insertCSS({
target: { tabId: tab.id },
files: ["test.css"],
}),
/Missing host permission for the tab/,
"insertCSS without permission should throw"
);
browser.test.notifyPass("finished");
},
"test.css": "body { background-color: red; }",
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["scripting"],
},
});
about3Pane.threadTree.selectedIndex = 1;
await awaitBrowserLoaded(messagePane);
await extension.startup();
await extension.awaitFinish("finished");
await checkMessageBody(
{
backgroundColor: "rgba(0, 0, 0, 0)",
textContent: "",
},
messages.at(-2)
);
await extension.unload();
});
/** Tests browser.scripting.executeScript. */
add_task(async function testExecuteScript() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const [tab] = await browser.tabs.query({ type: ["mail"] });
await window.sendMessage();
await browser.scripting.executeScript({
target: { tabId: tab.id },
func: () => {
document.body.setAttribute("foo", "bar");
},
});
await window.sendMessage();
await browser.scripting.executeScript({
target: { tabId: tab.id },
files: ["test.js"],
});
browser.test.notifyPass("finished");
},
"test.js": () => {
document.body.querySelector(".moz-text-flowed").textContent +=
"Hey look, the script ran!";
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["messagesModify", "scripting"],
},
});
about3Pane.threadTree.selectedIndex = 2;
await awaitBrowserLoaded(messagePane);
await extension.startup();
await extension.awaitMessage();
await checkMessageBody({ textContent: "" }, messages.at(-3));
extension.sendMessage();
await extension.awaitMessage();
await checkMessageBody({ foo: "bar" }, messages.at(-3));
extension.sendMessage();
await extension.awaitFinish("finished");
await checkMessageBody(
{
foo: "bar",
textContent: "Hey look, the script ran!",
},
messages.at(-3)
);
await extension.unload();
});
/** Tests browser.scripting.executeScript fails without the "messagesModify" permission. */
add_task(async function testExecuteScriptNoHostPermissions() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const [tab] = await browser.tabs.query({ type: ["mail"] });
await browser.test.assertRejects(
browser.scripting.executeScript({
target: { tabId: tab.id },
func: () => {
document.body.setAttribute("foo", "bar");
},
}),
/Missing host permission for the tab/,
"executeScript without permission should throw"
);
await browser.test.assertRejects(
browser.scripting.executeScript({
target: { tabId: tab.id },
files: ["test.js"],
}),
/Missing host permission for the tab/,
"executeScript without permission should throw"
);
await browser.test.assertRejects(
browser.scripting.executeScript({
target: { tabId: tab.id },
files: ["test.js"],
}),
/Missing host permission for the tab/,
"executeScript without permission should throw"
);
browser.test.notifyPass("finished");
},
"test.js": () => {
document.body.querySelector(".moz-text-flowed").textContent +=
"Hey look, the script ran!";
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["scripting"],
},
});
about3Pane.threadTree.selectedIndex = 3;
await awaitBrowserLoaded(messagePane);
await extension.startup();
await extension.awaitFinish("finished");
await checkMessageBody({ foo: null, textContent: "" }, messages.at(-4));
await extension.unload();
});
/** Tests the messenger alias is available. */
add_task(async function testExecuteScriptAlias() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
const [tab] = await browser.tabs.query({ type: ["mail"] });
await window.sendMessage();
await browser.scripting.executeScript({
target: { tabId: tab.id },
func: () => {
// eslint-disable-next-line no-undef
const id = messenger.runtime.getManifest().applications.gecko.id;
document.body.querySelector(".moz-text-flowed").textContent += id;
},
});
browser.test.notifyPass("finished");
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
browser_specific_settings: {
gecko: { id: "message_display_scripts@mochitest" },
},
background: { scripts: ["utils.js", "background.js"] },
permissions: ["messagesModify", "scripting"],
},
});
about3Pane.threadTree.selectedIndex = 3;
await awaitBrowserLoaded(messagePane);
await extension.startup();
await extension.awaitMessage();
await checkMessageBody({ textContent: "" }, messages.at(-4));
extension.sendMessage();
await extension.awaitFinish("finished");
await checkMessageBody(
{ textContent: "message_display_scripts@mochitest" },
messages.at(-4)
);
await extension.unload();
});
/**
* Tests browser.messageDisplayScripts.register correctly adds CSS and
* JavaScript to message display windows. Also tests calling `unregister`
* on the returned object.
*/
add_task(async function testRegister() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
// Keep track of registered scrips being executed and ready.
browser.runtime.onMessage.addListener((message, sender) => {
if (message == "LOADED") {
window.sendMessage("ScriptLoaded", sender.tab.id);
}
});
const registeredScript = await browser.messageDisplayScripts.register({
css: [{ code: "body { color: white }" }, { file: "test.css" }],
js: [
{ code: `document.body.setAttribute("foo", "bar");` },
{ file: "test.js" },
],
});
browser.test.onMessage.addListener(async (message, data) => {
switch (message) {
case "Unregister":
await registeredScript.unregister();
browser.test.notifyPass("finished");
break;
case "RuntimeMessageTest":
try {
browser.test.assertEq(
`Received: ${data.tabId}`,
await browser.tabs.sendMessage(data.tabId, data.tabId)
);
} catch (ex) {
browser.test.fail(
`Failed to send message to messageDisplayScript: ${ex}`
);
}
browser.test.sendMessage("RuntimeMessageTestDone");
break;
}
});
window.sendMessage("Ready");
},
"test.css": "body { background-color: green; }",
"test.js": () => {
document.body.querySelector(".moz-text-flowed").textContent +=
"Hey look, the script ran!";
browser.runtime.onMessage.addListener(async message => {
return `Received: ${message}`;
});
browser.runtime.sendMessage("LOADED");
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["messagesModify", "scripting"],
host_permissions: ["<all_urls>"],
},
});
about3Pane.threadTree.selectedIndex = 5;
await awaitBrowserLoaded(messagePane);
extension.startup();
await extension.awaitMessage("Ready");
// Check a message that was already loaded. This tab has not loaded the
// registered scripts.
await checkMessageBody(
{
backgroundColor: "rgba(0, 0, 0, 0)",
textContent: "",
},
messages.at(-6)
);
// Load a new message and check it is modified.
let loadPromise = extension.awaitMessage("ScriptLoaded");
about3Pane.threadTree.selectedIndex = 6;
const tabId = await loadPromise;
await checkMessageBody(
{
backgroundColor: "rgb(0, 128, 0)",
color: "rgb(255, 255, 255)",
foo: "bar",
textContent: "Hey look, the script ran!",
},
messages.at(-7)
);
// Check runtime messaging.
let testDonePromise = extension.awaitMessage("RuntimeMessageTestDone");
extension.sendMessage("RuntimeMessageTest", { tabId });
await testDonePromise;
// Open the message in a new tab.
loadPromise = extension.awaitMessage("ScriptLoaded");
const messageTab = await openMessageInTab(messages.at(-7));
const messageTabId = await loadPromise;
Assert.equal(tabmail.tabInfo.length, 2);
await checkMessageBody(
{
backgroundColor: "rgb(0, 128, 0)",
color: "rgb(255, 255, 255)",
foo: "bar",
textContent: "Hey look, the script ran!",
},
messages.at(-7),
messageTab.browser
);
// Check runtime messaging.
testDonePromise = extension.awaitMessage("RuntimeMessageTestDone");
extension.sendMessage("RuntimeMessageTest", { tabId: messageTabId });
await testDonePromise;
// Open a content tab. The CSS and script shouldn't apply.
const contentTab = window.openContentTab("http://mochi.test:8888/");
// Let's wait a while and see if anything happens:
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(resolve => setTimeout(resolve, 1000));
await checkMessageBody(
{
backgroundColor: "rgba(0, 0, 0, 0)",
color: "rgb(0, 0, 0)",
foo: null,
},
undefined,
contentTab.browser
);
// Closing this tab should bring us back to the message in a tab.
tabmail.closeTab(contentTab);
Assert.equal(tabmail.currentTabInfo, messageTab);
await checkMessageBody(
{
backgroundColor: "rgb(0, 128, 0)",
color: "rgb(255, 255, 255)",
foo: "bar",
textContent: "Hey look, the script ran!",
},
messages.at(-7),
messageTab.browser
);
// Check runtime messaging.
testDonePromise = extension.awaitMessage("RuntimeMessageTestDone");
extension.sendMessage("RuntimeMessageTest", { tabId: messageTabId });
await testDonePromise;
// Open the message in a new window.
loadPromise = extension.awaitMessage("ScriptLoaded");
const newWindow = await openMessageInWindow(messages.at(-8));
const newWindowMessagePane = newWindow.getBrowser();
const windowTabId = await loadPromise;
await checkMessageBody(
{
backgroundColor: "rgb(0, 128, 0)",
color: "rgb(255, 255, 255)",
foo: "bar",
textContent: "Hey look, the script ran!",
},
messages.at(-8),
newWindowMessagePane
);
// Check runtime messaging.
testDonePromise = extension.awaitMessage("RuntimeMessageTestDone");
extension.sendMessage("RuntimeMessageTest", { tabId: windowTabId });
await testDonePromise;
// Unregister.
extension.sendMessage("Unregister");
await extension.awaitFinish("finished");
await extension.unload();
// Check the CSS is unloaded from the message in a tab.
await checkMessageBody(
{
backgroundColor: "rgba(0, 0, 0, 0)",
color: "rgb(0, 0, 0)",
foo: "bar",
textContent: "Hey look, the script ran!",
},
messages.at(-7),
messageTab.browser
);
// Close the new tab.
tabmail.closeTab(messageTab);
await checkMessageBody(
{
backgroundColor: "rgba(0, 0, 0, 0)",
color: "rgb(0, 0, 0)",
foo: "bar",
textContent: "Hey look, the script ran!",
},
messages.at(-7)
);
// Check the CSS is unloaded from the message in a window.
await checkMessageBody(
{
backgroundColor: "rgba(0, 0, 0, 0)",
color: "rgb(0, 0, 0)",
foo: "bar",
textContent: "Hey look, the script ran!",
},
messages.at(-8),
newWindowMessagePane
);
await BrowserTestUtils.closeWindow(newWindow);
});
/** Tests content_scripts in the manifest do not affect message display. */
async function subtestContentScriptManifest(message, permissions) {
const extension = ExtensionTestUtils.loadExtension({
files: {
"test.css": "body { background-color: red; }",
"test.js": () => {
document.body.textContent += "Hey look, the script ran!";
},
},
manifest: {
manifest_version: 3,
permissions,
content_scripts: [
{
matches: ["<all_urls>"],
css: ["test.css"],
js: ["test.js"],
match_about_blank: true,
match_origin_as_fallback: true,
},
],
},
});
// match_origin_as_fallback is not implemented yet. Bug 1475831.
ExtensionTestUtils.failOnSchemaWarnings(false);
await extension.startup();
ExtensionTestUtils.failOnSchemaWarnings(true);
await checkMessageBody(
{
backgroundColor: "rgba(0, 0, 0, 0)",
textContent: "",
},
message
);
await extension.unload();
}
add_task(async function testContentScriptManifestNoPermission() {
about3Pane.threadTree.selectedIndex = 7;
await awaitBrowserLoaded(messagePane);
await subtestContentScriptManifest(messages.at(-8));
});
add_task(async function testContentScriptManifest() {
about3Pane.threadTree.selectedIndex = 8;
await awaitBrowserLoaded(messagePane);
await subtestContentScriptManifest(messages.at(-9), ["messagesModify"]);
});
/** Tests registered content scripts do not affect message display. */
async function subtestContentScriptRegister(message, permissions) {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
await browser.scripting.registerContentScripts([
{
id: "test",
matches: ["<all_urls>"],
css: ["test.css"],
js: ["test.js"],
},
]);
browser.test.notifyPass("finished");
},
"test.css": "body { background-color: red; }",
"test.js": () => {
document.body.querySelector(".moz-text-flowed").textContent +=
"Hey look, the script ran!";
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions,
host_permissions: ["<all_urls>"],
},
});
await extension.startup();
await extension.awaitFinish("finished");
await checkMessageBody(
{
backgroundColor: "rgba(0, 0, 0, 0)",
textContent: "",
},
message
);
await extension.unload();
}
add_task(async function testContentScriptRegisterNoPermission() {
about3Pane.threadTree.selectedIndex = 9;
await awaitBrowserLoaded(messagePane);
await subtestContentScriptRegister(messages.at(-10), ["scripting"]);
});
add_task(async function testContentScriptRegister() {
about3Pane.threadTree.selectedIndex = 10;
await awaitBrowserLoaded(messagePane);
await subtestContentScriptRegister(messages.at(-11), [
"scripting",
"messagesModify",
]);
});
/**
* Tests if scripts are correctly injected according to their runAt option.
*/
add_task(async function testRunAt() {
const extension = ExtensionTestUtils.loadExtension({
files: {
"background.js": async () => {
// Report script results.
browser.runtime.onMessage.addListener((message, sender) => {
if (message?.runAt) {
window.sendMessage(`ScriptLoaded:${message.runAt}`, {
senderTabId: sender.tab.id,
...message,
});
}
});
const registeredScripts = new Set();
registeredScripts.add(
await browser.messageDisplayScripts.register({
runAt: "document_start",
js: [{ file: "start.js" }],
})
);
registeredScripts.add(
await browser.messageDisplayScripts.register({
runAt: "document_end",
js: [{ file: "end.js" }],
})
);
registeredScripts.add(
await browser.messageDisplayScripts.register({
runAt: "document_idle",
js: [{ file: "idle.js" }],
})
);
browser.test.onMessage.addListener(async message => {
switch (message) {
case "Unregister":
for (const registeredScript of registeredScripts) {
await registeredScript.unregister();
}
browser.test.notifyPass("finished");
break;
}
});
browser.test.sendMessage("Ready");
},
"start.js": () => {
browser.runtime.sendMessage({
runAt: "document_start",
readyState: document?.readyState,
document: !!document,
body: !!document?.body,
textContent:
document.querySelector(".moz-text-flowed")?.textContent ?? "",
});
},
"end.js": () => {
browser.runtime.sendMessage({
runAt: "document_end",
readyState: document?.readyState,
document: !!document,
body: !!document?.body,
textContent:
document.querySelector(".moz-text-flowed")?.textContent ?? "",
});
},
"idle.js": () => {
browser.runtime.sendMessage({
runAt: "document_idle",
readyState: document?.readyState,
document: !!document,
body: !!document?.body,
textContent:
document.querySelector(".moz-text-flowed")?.textContent ?? "",
});
},
"utils.js": await getUtilsJS(),
},
manifest: {
manifest_version: 3,
background: { scripts: ["utils.js", "background.js"] },
permissions: ["messagesModify", "scripting"],
host_permissions: ["<all_urls>"],
},
});
about3Pane.threadTree.selectedIndex = 2;
await awaitBrowserLoaded(messagePane);
extension.startup();
await extension.awaitMessage("Ready");
function verifyResult(result, expected_individual) {
const expected_standard = [
{
runAt: "document_start",
readyState: "loading",
document: true,
body: false,
},
{
runAt: "document_end",
readyState: "interactive",
document: true,
body: true,
},
{
runAt: "document_idle",
readyState: "complete",
document: true,
body: true,
},
];
for (let i = 0; i < result.length; i++) {
Assert.equal(
expected_standard[i].runAt,
result[i].runAt,
`The 'runAt' value for state #${i} should be correct`
);
Assert.equal(
expected_standard[i].readyState,
result[i].readyState,
`The 'readyState' value at state #${i} should be correct`
);
Assert.equal(
expected_standard[i].document,
result[i].document,
`The document element at state #${i} ${
expected_standard[i].document ? "should" : "should not"
} exist`
);
Assert.equal(
expected_standard[i].body,
result[i].body,
`The body element at state #${i} ${
expected_standard[i].body ? "should" : "should not"
} exist`
);
Assert.equal(
expected_individual[i].textContent.trim(),
result[i].textContent.trim(),
`The content at state #${i} should be correct`
);
}
}
// Select a new message.
const firstLoadPromise = Promise.all([
extension.awaitMessage("ScriptLoaded:document_start"),
extension.awaitMessage("ScriptLoaded:document_end"),
extension.awaitMessage("ScriptLoaded:document_idle"),
]);
about3Pane.threadTree.selectedIndex = 3;
verifyResult(await firstLoadPromise, [
{ textContent: "" },
{ textContent: "Hello Pete Price!" },
{ textContent: "Hello Pete Price!" },
]);
// Select a different message.
const secondLoadPromise = Promise.all([
extension.awaitMessage("ScriptLoaded:document_start"),
extension.awaitMessage("ScriptLoaded:document_end"),
extension.awaitMessage("ScriptLoaded:document_idle"),
]);
about3Pane.threadTree.selectedIndex = 4;
verifyResult(await secondLoadPromise, [
{ textContent: "" },
{ textContent: "Hello Neil Nagel!" },
{ textContent: "Hello Neil Nagel!" },
]);
// Open the message in a new tab.
const thirdLoadPromise = Promise.all([
extension.awaitMessage("ScriptLoaded:document_start"),
extension.awaitMessage("ScriptLoaded:document_end"),
extension.awaitMessage("ScriptLoaded:document_idle"),
]);
const messageTab = await openMessageInTab(messages.at(-6));
verifyResult(await thirdLoadPromise, [
{ textContent: "" },
{ textContent: "Hello Lilia Lowe!" },
{ textContent: "Hello Lilia Lowe!" },
]);
Assert.equal(tabmail.tabInfo.length, 2);
// Open a content tab. The message display scripts should not be injected.
// If they DO get injected, we will end up with 3 additional messages from the
// extension and the test will fail.
const contentTab = window.openContentTab("http://mochi.test:8888/");
Assert.equal(tabmail.tabInfo.length, 3);
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(resolve => setTimeout(resolve, 1000));
// Closing this tab should bring us back to the message in a tab.
tabmail.closeTab(contentTab);
Assert.equal(tabmail.tabInfo.length, 2);
Assert.equal(tabmail.currentTabInfo, messageTab);
// Open the message in a new window.
const fourthLoadPromise = Promise.all([
extension.awaitMessage("ScriptLoaded:document_start"),
extension.awaitMessage("ScriptLoaded:document_end"),
extension.awaitMessage("ScriptLoaded:document_idle"),
]);
const newWindow = await openMessageInWindow(messages.at(-7));
verifyResult(await fourthLoadPromise, [
{ textContent: "" },
{ textContent: "Hello Johnny Jones!" },
{ textContent: "Hello Johnny Jones!" },
]);
// Unregister.
extension.sendMessage("Unregister");
await extension.awaitFinish("finished");
await extension.unload();
// Close the new tab.
tabmail.closeTab(messageTab);
await BrowserTestUtils.closeWindow(newWindow);
});