summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions/test
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:43:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:43:14 +0000
commit8dd16259287f58f9273002717ec4d27e97127719 (patch)
tree3863e62a53829a84037444beab3abd4ed9dfc7d0 /toolkit/mozapps/extensions/test
parentReleasing progress-linux version 126.0.1-1~progress7.99u1. (diff)
downloadfirefox-8dd16259287f58f9273002717ec4d27e97127719.tar.xz
firefox-8dd16259287f58f9273002717ec4d27e97127719.zip
Merging upstream version 127.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/mozapps/extensions/test')
-rw-r--r--toolkit/mozapps/extensions/test/browser/browser.toml14
-rw-r--r--toolkit/mozapps/extensions/test/browser/browser_amo_abuse_report.js21
-rw-r--r--toolkit/mozapps/extensions/test/browser/browser_html_abuse_report.js1091
-rw-r--r--toolkit/mozapps/extensions/test/browser/browser_html_abuse_report_dialog.js185
-rw-r--r--toolkit/mozapps/extensions/test/browser/browser_html_detail_permissions.js44
-rw-r--r--toolkit/mozapps/extensions/test/browser/browser_html_detail_view.js6
-rw-r--r--toolkit/mozapps/extensions/test/browser/browser_html_discover_view.js7
-rw-r--r--toolkit/mozapps/extensions/test/browser/browser_html_message_bar.js185
-rw-r--r--toolkit/mozapps/extensions/test/browser/browser_html_options_ui_dark_theme.js173
-rw-r--r--toolkit/mozapps/extensions/test/browser/browser_html_scroll_restoration.js14
-rw-r--r--toolkit/mozapps/extensions/test/browser/browser_webapi_abuse_report.js375
-rw-r--r--toolkit/mozapps/extensions/test/browser/head_abuse_report.js492
-rw-r--r--toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js687
-rw-r--r--toolkit/mozapps/extensions/test/xpcshell/test_dictionary_webextension.js15
-rw-r--r--toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js196
-rw-r--r--toolkit/mozapps/extensions/test/xpcshell/xpcshell.toml199
-rw-r--r--toolkit/mozapps/extensions/test/xpinstall/browser_required_useractivation.js1
17 files changed, 633 insertions, 3072 deletions
diff --git a/toolkit/mozapps/extensions/test/browser/browser.toml b/toolkit/mozapps/extensions/test/browser/browser.toml
index 6556b95584..b43064da16 100644
--- a/toolkit/mozapps/extensions/test/browser/browser.toml
+++ b/toolkit/mozapps/extensions/test/browser/browser.toml
@@ -55,6 +55,7 @@ prefs = [
["browser_addon_list_reordering.js"]
["browser_amo_abuse_report.js"]
+support-files = ["head_abuse_report.js"]
["browser_bug572561.js"]
@@ -77,12 +78,6 @@ skip-if = ["true"] # Bug 1626824
["browser_history_navigation.js"]
https_first_disabled = true
-["browser_html_abuse_report.js"]
-support-files = ["head_abuse_report.js"]
-
-["browser_html_abuse_report_dialog.js"]
-support-files = ["head_abuse_report.js"]
-
["browser_html_detail_permissions.js"]
["browser_html_detail_view.js"]
@@ -100,10 +95,10 @@ support-files = ["head_disco.js"]
["browser_html_list_view_recommendations.js"]
skip-if = ["a11y_checks"] # Bug 1858037 to investigate intermittent a11y_checks results for .popup-notification-primary-button.primary.footer-button
-["browser_html_message_bar.js"]
-
["browser_html_options_ui.js"]
+["browser_html_options_ui_dark_theme.js"]
+
["browser_html_options_ui_in_tab.js"]
["browser_html_pending_updates.js"]
@@ -169,9 +164,6 @@ https_first_disabled = true
["browser_webapi.js"]
-["browser_webapi_abuse_report.js"]
-support-files = ["head_abuse_report.js"]
-
["browser_webapi_access.js"]
https_first_disabled = true
diff --git a/toolkit/mozapps/extensions/test/browser/browser_amo_abuse_report.js b/toolkit/mozapps/extensions/test/browser/browser_amo_abuse_report.js
index b470cf2d82..7cd2d5d57d 100644
--- a/toolkit/mozapps/extensions/test/browser/browser_amo_abuse_report.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_amo_abuse_report.js
@@ -15,26 +15,7 @@ add_setup(async () => {
],
});
- // Explicitly flip the amoFormEnabled pref on builds where the pref is
- // expected to not be set to true by default.
- if (AppConstants.MOZ_APP_NAME != "firefox") {
- await SpecialPowers.pushPrefEnv({
- set: [["extensions.abuseReport.amoFormEnabled", true]],
- });
- }
-
- const { AbuseReporter } = ChromeUtils.importESModule(
- "resource://gre/modules/AbuseReporter.sys.mjs"
- );
-
- Assert.equal(
- AbuseReporter.amoFormEnabled,
- true,
- "Expect AMO abuse report form to be enabled"
- );
-
- // Setting up MockProvider to mock various addon types
- // as installed.
+ // Setting up MockProvider to mock various addon types as installed.
await AbuseReportTestUtils.setup();
});
diff --git a/toolkit/mozapps/extensions/test/browser/browser_html_abuse_report.js b/toolkit/mozapps/extensions/test/browser/browser_html_abuse_report.js
deleted file mode 100644
index f20e5b357b..0000000000
--- a/toolkit/mozapps/extensions/test/browser/browser_html_abuse_report.js
+++ /dev/null
@@ -1,1091 +0,0 @@
-/* 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/. */
-/* eslint max-len: ["error", 80] */
-
-loadTestSubscript("head_abuse_report.js");
-
-add_setup(async function () {
- // Make sure the integrated abuse report panel is the one enabled
- // while this test file runs (instead of the AMO hosted form).
- // NOTE: behaviors expected when amoFormEnabled is true are tested
- // in the separate browser_amo_abuse_report.js test file.
- await SpecialPowers.pushPrefEnv({
- set: [["extensions.abuseReport.amoFormEnabled", false]],
- });
- await AbuseReportTestUtils.setup();
-});
-
-/**
- * Base tests on abuse report panel webcomponents.
- */
-
-// This test case verified that the abuse report panels contains a radio
-// button for all the expected "abuse report reasons", they are grouped
-// together under the same form field named "reason".
-add_task(async function test_abusereport_issuelist() {
- const extension = await installTestExtension();
-
- const abuseReportEl = await AbuseReportTestUtils.openReport(extension.id);
-
- const reasonsPanel = abuseReportEl._reasonsPanel;
- const radioButtons = reasonsPanel.querySelectorAll("[type=radio]");
- const selectedRadios = reasonsPanel.querySelectorAll("[type=radio]:checked");
-
- is(selectedRadios.length, 1, "Expect only one radio button selected");
- is(
- selectedRadios[0],
- radioButtons[0],
- "Expect the first radio button to be selected"
- );
-
- is(
- abuseReportEl.reason,
- radioButtons[0].value,
- `The reason property has the expected value: ${radioButtons[0].value}`
- );
-
- const reasons = Array.from(radioButtons).map(el => el.value);
- Assert.deepEqual(
- reasons.sort(),
- AbuseReportTestUtils.getReasons(abuseReportEl).sort(),
- `Got a radio button for the expected reasons`
- );
-
- for (const radio of radioButtons) {
- const reasonInfo = AbuseReportTestUtils.getReasonInfo(
- abuseReportEl,
- radio.value
- );
- const expectExampleHidden =
- reasonInfo && reasonInfo.isExampleHidden("extension");
- is(
- radio.parentNode.querySelector(".reason-example").hidden,
- expectExampleHidden,
- `Got expected visibility on the example for reason "${radio.value}"`
- );
- }
-
- info("Change the selected reason to " + radioButtons[3].value);
- radioButtons[3].checked = true;
- is(
- abuseReportEl.reason,
- radioButtons[3].value,
- "The reason property has the expected value"
- );
-
- await extension.unload();
- await closeAboutAddons();
-});
-
-// This test case verifies that the abuse report panel:
-// - switches from its "reasons list" mode to its "submit report" mode when the
-// "next" button is clicked
-// - goes back to the "reasons list" mode when the "go back" button is clicked
-// - the abuse report panel is closed when the "close" icon is clicked
-add_task(async function test_abusereport_submitpanel() {
- const extension = await installTestExtension();
-
- const abuseReportEl = await AbuseReportTestUtils.openReport(extension.id);
-
- ok(
- !abuseReportEl._reasonsPanel.hidden,
- "The list of abuse reasons is the currently visible"
- );
- ok(
- abuseReportEl._submitPanel.hidden,
- "The submit panel is the currently hidden"
- );
-
- let onceUpdated = AbuseReportTestUtils.promiseReportUpdated(
- abuseReportEl,
- "submit"
- );
- const MozButtonGroup =
- abuseReportEl.ownerGlobal.customElements.get("moz-button-group");
-
- ok(MozButtonGroup, "Expect MozButtonGroup custom element to be defined");
-
- const assertButtonInMozButtonGroup = (
- btnEl,
- { expectPrimary = false } = {}
- ) => {
- // Let's include the l10n id into the assertion messages,
- // to make it more likely to be immediately clear which
- // button hit a failure if any of the following assertion
- // fails.
- let l10nId = btnEl.getAttribute("data-l10n-id");
- is(
- btnEl.classList.contains("primary"),
- expectPrimary,
- `Expect button ${l10nId} to have${
- expectPrimary ? "" : " NOT"
- } the primary class set`
- );
-
- ok(
- btnEl.parentElement instanceof MozButtonGroup,
- `Expect button ${l10nId} to be slotted inside the expected custom element`
- );
-
- is(
- btnEl.getAttribute("slot"),
- expectPrimary ? "primary" : null,
- `Expect button ${l10nId} slot to ${
- expectPrimary ? "" : "NOT "
- } be set to primary`
- );
- };
-
- // Verify button group from the initial panel.
- assertButtonInMozButtonGroup(abuseReportEl._btnNext, { expectPrimary: true });
- assertButtonInMozButtonGroup(abuseReportEl._btnCancel, {
- expectPrimary: false,
- });
- await AbuseReportTestUtils.clickPanelButton(abuseReportEl._btnNext);
- await onceUpdated;
- // Verify button group from the submit panel mode.
- assertButtonInMozButtonGroup(abuseReportEl._btnSubmit, {
- expectPrimary: true,
- });
- assertButtonInMozButtonGroup(abuseReportEl._btnGoBack, {
- expectPrimary: false,
- });
- onceUpdated = AbuseReportTestUtils.promiseReportUpdated(
- abuseReportEl,
- "reasons"
- );
- await AbuseReportTestUtils.clickPanelButton(abuseReportEl._btnGoBack);
- await onceUpdated;
-
- const onceReportClosed =
- AbuseReportTestUtils.promiseReportClosed(abuseReportEl);
- await AbuseReportTestUtils.clickPanelButton(abuseReportEl._btnCancel);
- await onceReportClosed;
-
- await extension.unload();
- await closeAboutAddons();
-});
-
-// This test case verifies that the abuse report panel sends the expected data
-// in the "abuse-report:submit" event detail.
-add_task(async function test_abusereport_submit() {
- // Reset the timestamp of the last report between tests.
- AbuseReporter._lastReportTimestamp = null;
- const extension = await installTestExtension();
-
- const abuseReportEl = await AbuseReportTestUtils.openReport(extension.id);
-
- ok(
- !abuseReportEl._reasonsPanel.hidden,
- "The list of abuse reasons is the currently visible"
- );
-
- let onceUpdated = AbuseReportTestUtils.promiseReportUpdated(
- abuseReportEl,
- "submit"
- );
- await AbuseReportTestUtils.clickPanelButton(abuseReportEl._btnNext);
- await onceUpdated;
-
- is(abuseReportEl.message, "", "The abuse report message is initially empty");
-
- info("Test typing a message in the abuse report submit panel textarea");
- const typedMessage = "Description of the extension abuse report";
-
- EventUtils.synthesizeComposition(
- {
- data: typedMessage,
- type: "compositioncommit",
- },
- abuseReportEl.ownerGlobal
- );
-
- is(
- abuseReportEl.message,
- typedMessage,
- "Got the expected typed message in the abuse report"
- );
-
- const expectedDetail = {
- addonId: extension.id,
- };
-
- const expectedReason = abuseReportEl.reason;
- const expectedMessage = abuseReportEl.message;
-
- function handleSubmitRequest({ request, response }) {
- response.setStatusLine(request.httpVersion, 200, "OK");
- response.setHeader("Content-Type", "application/json", false);
- response.write("{}");
- }
-
- let reportSubmitted;
- const onReportSubmitted = AbuseReportTestUtils.promiseReportSubmitHandled(
- ({ data, request, response }) => {
- reportSubmitted = JSON.parse(data);
- handleSubmitRequest({ request, response });
- }
- );
-
- const onceReportClosed =
- AbuseReportTestUtils.promiseReportClosed(abuseReportEl);
-
- const onMessageBarsCreated = AbuseReportTestUtils.promiseMessageBars(2);
-
- const onceSubmitEvent = BrowserTestUtils.waitForEvent(
- abuseReportEl,
- "abuse-report:submit"
- );
- await AbuseReportTestUtils.clickPanelButton(abuseReportEl._btnSubmit);
- const submitEvent = await onceSubmitEvent;
-
- const actualDetail = {
- addonId: submitEvent.detail.addonId,
- };
- Assert.deepEqual(
- actualDetail,
- expectedDetail,
- "Got the expected detail in the abuse-report:submit event"
- );
-
- ok(
- submitEvent.detail.report,
- "Got a report object in the abuse-report:submit event detail"
- );
-
- // Verify that, when the "abuse-report:submit" has been sent,
- // the abuse report panel has been hidden, the report has been
- // submitted and the expected message bar is created in the
- // HTML about:addons page.
- info("Wait the report to be submitted to the api server");
- await onReportSubmitted;
- info("Wait the report panel to be closed");
- await onceReportClosed;
-
- is(
- reportSubmitted.addon,
- ADDON_ID,
- "Got the expected addon in the submitted report"
- );
- is(
- reportSubmitted.reason,
- expectedReason,
- "Got the expected reason in the submitted report"
- );
- is(
- reportSubmitted.message,
- expectedMessage,
- "Got the expected message in the submitted report"
- );
- is(
- reportSubmitted.report_entry_point,
- REPORT_ENTRY_POINT,
- "Got the expected report_entry_point in the submitted report"
- );
-
- info("Waiting the expected message bars to be created");
- const barDetails = await onMessageBarsCreated;
- is(barDetails.length, 2, "Expect two message bars to have been created");
- is(
- barDetails[0].definitionId,
- "submitting",
- "Got a submitting message bar as expected"
- );
- is(
- barDetails[1].definitionId,
- "submitted",
- "Got a submitted message bar as expected"
- );
-
- await extension.unload();
- await closeAboutAddons();
-});
-
-// This helper does verify that the abuse report panel contains the expected
-// suggestions when the selected reason requires it (and urls are being set
-// on the links elements included in the suggestions when expected).
-async function test_abusereport_suggestions(addonId) {
- const addon = await AddonManager.getAddonByID(addonId);
-
- const abuseReportEl = await AbuseReportTestUtils.openReport(addonId);
-
- const {
- _btnNext,
- _btnGoBack,
- _reasonsPanel,
- _submitPanel,
- _submitPanel: { _suggestions },
- } = abuseReportEl;
-
- for (const reason of AbuseReportTestUtils.getReasons(abuseReportEl)) {
- const reasonInfo = AbuseReportTestUtils.getReasonInfo(
- abuseReportEl,
- reason
- );
-
- // TODO(Bug 1789718): Remove after the deprecated XPIProvider-based
- // implementation is also removed.
- const addonType =
- addon.type === "sitepermission-deprecated"
- ? "sitepermission"
- : addon.type;
-
- if (reasonInfo.isReasonHidden(addonType)) {
- continue;
- }
-
- info(`Test suggestions for abuse reason "${reason}"`);
-
- // Select a reason with suggestions.
- let radioEl = abuseReportEl.querySelector(`#abuse-reason-${reason}`);
- ok(radioEl, `Found radio button for "${reason}"`);
- radioEl.checked = true;
-
- // Make sure the element localization is completed before
- // checking the content isn't empty.
- await document.l10n.translateFragment(radioEl);
-
- // Verify each radio button has a non-empty localized string.
- const localizedRadioContent = Array.from(
- radioEl.closest("label").querySelectorAll("[data-l10n-id]")
- ).filter(el => !el.hidden);
-
- for (let el of localizedRadioContent) {
- isnot(
- el.textContent,
- "",
- `Fluent string id '${el.getAttribute("data-l10n-id")}' missing`
- );
- }
-
- // Switch to the submit form with the current reason radio selected.
- let oncePanelUpdated = AbuseReportTestUtils.promiseReportUpdated(
- abuseReportEl,
- "submit"
- );
- await AbuseReportTestUtils.clickPanelButton(_btnNext);
- await oncePanelUpdated;
-
- const localizedSuggestionsContent = Array.from(
- _suggestions.querySelectorAll("[data-l10n-id]")
- ).filter(el => !el.hidden);
-
- is(
- !_suggestions.hidden,
- !!reasonInfo.hasSuggestions,
- `Suggestions block has the expected visibility for "${reason}"`
- );
- if (reasonInfo.hasSuggestions) {
- ok(
- !!localizedSuggestionsContent.length,
- `Category suggestions should not be empty for "${reason}"`
- );
- } else {
- Assert.strictEqual(
- localizedSuggestionsContent.length,
- 0,
- `Category suggestions should be empty for "${reason}"`
- );
- }
-
- const extSupportLink = _suggestions.querySelector(
- ".extension-support-link"
- );
- if (extSupportLink) {
- is(
- extSupportLink.getAttribute("href"),
- BASE_TEST_MANIFEST.homepage_url,
- "Got the expected extension-support-url"
- );
- }
-
- const learnMoreLinks = [];
- learnMoreLinks.push(
- ..._suggestions.querySelectorAll(
- 'a[is="moz-support-link"], .abuse-policy-learnmore'
- )
- );
-
- if (learnMoreLinks.length) {
- is(
- _suggestions.querySelectorAll(
- 'a[is="moz-support-link"]:not([support-page])'
- ).length,
- 0,
- "Every SUMO link should point to a specific page"
- );
- ok(
- learnMoreLinks.every(el => el.getAttribute("target") === "_blank"),
- "All the learn more links have target _blank"
- );
- ok(
- learnMoreLinks.every(el => el.hasAttribute("href")),
- "All the learn more links have a url set"
- );
- }
-
- oncePanelUpdated = AbuseReportTestUtils.promiseReportUpdated(
- abuseReportEl,
- "reasons"
- );
- await AbuseReportTestUtils.clickPanelButton(_btnGoBack);
- await oncePanelUpdated;
- ok(!_reasonsPanel.hidden, "Reasons panel should be visible");
- ok(_submitPanel.hidden, "Submit panel should be hidden");
- }
-
- await closeAboutAddons();
-}
-
-add_task(async function test_abusereport_suggestions_extension() {
- const EXT_ID = "test-extension-suggestions@mochi.test";
- const extension = await installTestExtension(EXT_ID);
- await test_abusereport_suggestions(EXT_ID);
- await extension.unload();
-});
-
-add_task(async function test_abusereport_suggestions_theme() {
- const THEME_ID = "theme@mochi.test";
- const theme = await installTestExtension(THEME_ID, "theme");
- await test_abusereport_suggestions(THEME_ID);
- await theme.unload();
-});
-
-// TODO(Bug 1789718): adapt to SitePermAddonProvider implementation.
-add_task(async function test_abusereport_suggestions_sitepermission() {
- const SITEPERM_ADDON_ID = "webmidi@mochi.test";
- const sitePermAddon = await installTestExtension(
- SITEPERM_ADDON_ID,
- "sitepermission-deprecated"
- );
- await test_abusereport_suggestions(SITEPERM_ADDON_ID);
- await sitePermAddon.unload();
-});
-
-// This test case verifies the message bars created on other
-// scenarios (e.g. report creation and submissions errors).
-//
-// TODO(Bug 1789718): adapt to SitePermAddonProvider implementation.
-add_task(async function test_abusereport_messagebars() {
- const EXT_ID = "test-extension-report@mochi.test";
- const EXT_ID2 = "test-extension-report-2@mochi.test";
- const THEME_ID = "test-theme-report@mochi.test";
- const SITEPERM_ADDON_ID = "webmidi-report@mochi.test";
- const extension = await installTestExtension(EXT_ID);
- const extension2 = await installTestExtension(EXT_ID2);
- const theme = await installTestExtension(THEME_ID, "theme");
- const sitePermAddon = await installTestExtension(
- SITEPERM_ADDON_ID,
- "sitepermission-deprecated"
- );
-
- async function assertMessageBars(
- expectedMessageBarIds,
- testSetup,
- testMessageBarDetails
- ) {
- await openAboutAddons();
- const expectedLength = expectedMessageBarIds.length;
- const onMessageBarsCreated =
- AbuseReportTestUtils.promiseMessageBars(expectedLength);
- // Reset the timestamp of the last report between tests.
- AbuseReporter._lastReportTimestamp = null;
- await testSetup();
- info(`Waiting for ${expectedLength} message-bars to be created`);
- const barDetails = await onMessageBarsCreated;
- Assert.deepEqual(
- barDetails.map(d => d.definitionId),
- expectedMessageBarIds,
- "Got the expected message bars"
- );
- if (testMessageBarDetails) {
- await testMessageBarDetails(barDetails);
- }
- await closeAboutAddons();
- }
-
- function setTestRequestHandler(responseStatus, responseData) {
- AbuseReportTestUtils.promiseReportSubmitHandled(({ request, response }) => {
- response.setStatusLine(request.httpVersion, responseStatus, "Error");
- response.write(responseData);
- });
- }
-
- await assertMessageBars(["ERROR_ADDON_NOTFOUND"], async () => {
- info("Test message bars on addon not found");
- AbuseReportTestUtils.triggerNewReport(
- "non-existend-addon-id@mochi.test",
- REPORT_ENTRY_POINT
- );
- });
-
- await assertMessageBars(["submitting", "ERROR_RECENT_SUBMIT"], async () => {
- info("Test message bars on recent submission");
- const promiseRendered = AbuseReportTestUtils.promiseReportRendered();
- AbuseReportTestUtils.triggerNewReport(EXT_ID, REPORT_ENTRY_POINT);
- await promiseRendered;
- AbuseReporter.updateLastReportTimestamp();
- AbuseReportTestUtils.triggerSubmit("fake-reason", "fake-message");
- });
-
- await assertMessageBars(["submitting", "ERROR_ABORTED_SUBMIT"], async () => {
- info("Test message bars on aborted submission");
- AbuseReportTestUtils.triggerNewReport(EXT_ID, REPORT_ENTRY_POINT);
- await AbuseReportTestUtils.promiseReportRendered();
- const { _report } = AbuseReportTestUtils.getReportPanel();
- _report.abort();
- AbuseReportTestUtils.triggerSubmit("fake-reason", "fake-message");
- });
-
- await assertMessageBars(["submitting", "ERROR_SERVER"], async () => {
- info("Test message bars on server error");
- setTestRequestHandler(500);
- AbuseReportTestUtils.triggerNewReport(EXT_ID, REPORT_ENTRY_POINT);
- await AbuseReportTestUtils.promiseReportRendered();
- AbuseReportTestUtils.triggerSubmit("fake-reason", "fake-message");
- });
-
- await assertMessageBars(["submitting", "ERROR_CLIENT"], async () => {
- info("Test message bars on client error");
- setTestRequestHandler(400);
- AbuseReportTestUtils.triggerNewReport(EXT_ID, REPORT_ENTRY_POINT);
- await AbuseReportTestUtils.promiseReportRendered();
- AbuseReportTestUtils.triggerSubmit("fake-reason", "fake-message");
- });
-
- await assertMessageBars(["submitting", "ERROR_UNKNOWN"], async () => {
- info("Test message bars on unexpected status code");
- setTestRequestHandler(604);
- AbuseReportTestUtils.triggerNewReport(EXT_ID, REPORT_ENTRY_POINT);
- await AbuseReportTestUtils.promiseReportRendered();
- AbuseReportTestUtils.triggerSubmit("fake-reason", "fake-message");
- });
-
- await assertMessageBars(["submitting", "ERROR_UNKNOWN"], async () => {
- info("Test message bars on invalid json in the response data");
- setTestRequestHandler(200, "");
- AbuseReportTestUtils.triggerNewReport(EXT_ID, REPORT_ENTRY_POINT);
- await AbuseReportTestUtils.promiseReportRendered();
- AbuseReportTestUtils.triggerSubmit("fake-reason", "fake-message");
- });
-
- // Verify message bar on add-on without perm_can_uninstall.
- await assertMessageBars(
- ["submitting", "submitted-no-remove-action"],
- async () => {
- info("Test message bars on report submitted on an addon without remove");
- setTestRequestHandler(200, "{}");
- AbuseReportTestUtils.triggerNewReport(THEME_NO_UNINSTALL_ID, "menu");
- await AbuseReportTestUtils.promiseReportRendered();
- AbuseReportTestUtils.triggerSubmit("fake-reason", "fake-message");
- }
- );
-
- // Verify the 3 expected entry points:
- // menu, toolbar_context_menu and uninstall
- // (See https://addons-server.readthedocs.io/en/latest/topics/api/abuse.html).
- await assertMessageBars(["submitting", "submitted"], async () => {
- info("Test message bars on report opened from addon options menu");
- setTestRequestHandler(200, "{}");
- AbuseReportTestUtils.triggerNewReport(EXT_ID, "menu");
- await AbuseReportTestUtils.promiseReportRendered();
- AbuseReportTestUtils.triggerSubmit("fake-reason", "fake-message");
- });
-
- for (const extId of [EXT_ID, THEME_ID]) {
- await assertMessageBars(
- ["submitting", "submitted"],
- async () => {
- info(`Test message bars on ${extId} reported from toolbar contextmenu`);
- setTestRequestHandler(200, "{}");
- AbuseReportTestUtils.triggerNewReport(extId, "toolbar_context_menu");
- await AbuseReportTestUtils.promiseReportRendered();
- AbuseReportTestUtils.triggerSubmit("fake-reason", "fake-message");
- },
- ([, submittedDetails]) => {
- const buttonsL10nId = Array.from(
- submittedDetails.messagebar.querySelectorAll("button")
- ).map(el => el.getAttribute("data-l10n-id"));
- if (extId === THEME_ID) {
- ok(
- buttonsL10nId.every(id => id.endsWith("-theme")),
- "submitted bar actions should use the Fluent id for themes"
- );
- } else {
- ok(
- buttonsL10nId.every(id => id.endsWith("-extension")),
- "submitted bar actions should use the Fluent id for extensions"
- );
- }
- }
- );
- }
-
- for (const extId of [EXT_ID2, THEME_ID, SITEPERM_ADDON_ID]) {
- const testFn = async () => {
- info(`Test message bars on ${extId} reported opened from addon removal`);
- setTestRequestHandler(200, "{}");
- AbuseReportTestUtils.triggerNewReport(extId, "uninstall");
- await AbuseReportTestUtils.promiseReportRendered();
- const addon = await AddonManager.getAddonByID(extId);
- // Ensure that the test extension is pending uninstall as it would be
- // when a user trigger this scenario on an actual addon uninstall.
- await addon.uninstall(true);
- AbuseReportTestUtils.triggerSubmit("fake-reason", "fake-message");
- };
- const assertMessageBarDetails = async ([, submittedDetails]) =>
- AbuseReportTestUtils.assertFluentStrings(submittedDetails.messagebar);
- await assertMessageBars(
- ["submitting", "submitted-and-removed"],
- testFn,
- assertMessageBarDetails
- );
- }
-
- // Verify message bar on sitepermission add-on type.
- await assertMessageBars(
- ["submitting", "submitted"],
- async () => {
- info(
- "Test message bars for report submitted on an sitepermission addon type"
- );
- setTestRequestHandler(200, "{}");
- AbuseReportTestUtils.triggerNewReport(SITEPERM_ADDON_ID, "menu");
- await AbuseReportTestUtils.promiseReportRendered();
- AbuseReportTestUtils.triggerSubmit("fake-reason", "fake-message");
- },
- ([, submittedDetails]) =>
- AbuseReportTestUtils.assertFluentStrings(submittedDetails.messagebar)
- );
-
- await extension.unload();
- await extension2.unload();
- await theme.unload();
- await sitePermAddon.unload();
-});
-
-add_task(async function test_abusereport_from_aboutaddons_menu() {
- const EXT_ID = "test-report-from-aboutaddons-menu@mochi.test";
- const extension = await installTestExtension(EXT_ID);
-
- await openAboutAddons();
-
- AbuseReportTestUtils.assertReportPanelHidden();
-
- const addonCard = gManagerWindow.document.querySelector(
- `addon-list addon-card[addon-id="${extension.id}"]`
- );
- ok(addonCard, "Got the addon-card for the test extension");
-
- const reportButton = addonCard.querySelector("[action=report]");
- ok(reportButton, "Got the report action for the test extension");
-
- info("Click the report action and wait for the 'abuse-report:new' event");
-
- let onceReportOpened = AbuseReportTestUtils.promiseReportOpened({
- addonId: extension.id,
- reportEntryPoint: "menu",
- });
- reportButton.click();
- const panelEl = await onceReportOpened;
-
- await AbuseReportTestUtils.closeReportPanel(panelEl);
-
- await closeAboutAddons();
- await extension.unload();
-});
-
-add_task(async function test_abusereport_from_aboutaddons_remove() {
- const EXT_ID = "test-report-from-aboutaddons-remove@mochi.test";
-
- // Test on a theme addon to cover the report checkbox included in the
- // uninstall dialog also on a theme.
- const extension = await installTestExtension(EXT_ID, "theme");
-
- await openAboutAddons("theme");
-
- AbuseReportTestUtils.assertReportPanelHidden();
-
- const addonCard = gManagerWindow.document.querySelector(
- `addon-list addon-card[addon-id="${extension.id}"]`
- );
- ok(addonCard, "Got the addon-card for the test theme extension");
-
- const removeButton = addonCard.querySelector("[action=remove]");
- ok(removeButton, "Got the remove action for the test theme extension");
-
- // Prepare the mocked prompt service.
- const promptService = mockPromptService();
- promptService.confirmEx = createPromptConfirmEx({
- remove: true,
- report: true,
- });
-
- info("Click the report action and wait for the 'abuse-report:new' event");
-
- const onceReportOpened = AbuseReportTestUtils.promiseReportOpened({
- addonId: extension.id,
- reportEntryPoint: "uninstall",
- });
- removeButton.click();
- const panelEl = await onceReportOpened;
-
- await AbuseReportTestUtils.closeReportPanel(panelEl);
-
- await closeAboutAddons();
- await extension.unload();
-});
-
-add_task(async function test_abusereport_from_browserAction_remove() {
- const EXT_ID = "test-report-from-browseraction-remove@mochi.test";
- const xpiFile = AddonTestUtils.createTempWebExtensionFile({
- manifest: {
- ...BASE_TEST_MANIFEST,
- browser_action: {
- default_area: "navbar",
- },
- browser_specific_settings: { gecko: { id: EXT_ID } },
- },
- });
- const addon = await AddonManager.installTemporaryAddon(xpiFile);
-
- const buttonId = `${makeWidgetId(EXT_ID)}-browser-action`;
-
- async function promiseAnimationFrame() {
- await new Promise(resolve => window.requestAnimationFrame(resolve));
-
- let { tm } = Services;
- return new Promise(resolve => tm.dispatchToMainThread(resolve));
- }
-
- async function reportFromContextMenuRemove() {
- const menu = document.getElementById("toolbar-context-menu");
- const node = document.getElementById(CSS.escape(buttonId));
- const shown = BrowserTestUtils.waitForEvent(
- menu,
- "popupshown",
- "Wair for contextmenu popup"
- );
-
- // Wait for an animation frame as we do for the other mochitest-browser
- // tests related to the browserActions.
- await promiseAnimationFrame();
- EventUtils.synthesizeMouseAtCenter(node, { type: "contextmenu" });
- await shown;
-
- info(`Clicking on "Remove Extension" context menu item`);
- let removeExtension = menu.querySelector(
- ".customize-context-removeExtension"
- );
- removeExtension.click();
-
- return menu;
- }
-
- // Prepare the mocked prompt service.
- const promptService = mockPromptService();
- promptService.confirmEx = createPromptConfirmEx({
- remove: true,
- report: true,
- });
-
- await BrowserTestUtils.withNewTab("about:blank", async function () {
- info(`Open browserAction context menu in toolbar context menu`);
- let promiseMenu = reportFromContextMenuRemove();
-
- // Wait about:addons to be loaded.
- let browser = gBrowser.selectedBrowser;
- await BrowserTestUtils.browserLoaded(browser);
-
- let onceReportOpened = AbuseReportTestUtils.promiseReportOpened({
- addonId: EXT_ID,
- reportEntryPoint: "uninstall",
- managerWindow: browser.contentWindow,
- });
-
- is(
- browser.currentURI.spec,
- "about:addons",
- "about:addons tab currently selected"
- );
-
- let menu = await promiseMenu;
- menu.hidePopup();
-
- let panelEl = await onceReportOpened;
-
- await AbuseReportTestUtils.closeReportPanel(panelEl);
-
- let onceExtStarted = AddonTestUtils.promiseWebExtensionStartup(EXT_ID);
- addon.cancelUninstall();
- await onceExtStarted;
-
- // Reload the tab to verify Bug 1559124 didn't regressed.
- browser.contentWindow.location.reload();
- await BrowserTestUtils.browserLoaded(browser);
- is(
- browser.currentURI.spec,
- "about:addons",
- "about:addons tab currently selected"
- );
-
- onceReportOpened = AbuseReportTestUtils.promiseReportOpened({
- addonId: EXT_ID,
- reportEntryPoint: "uninstall",
- managerWindow: browser.contentWindow,
- });
-
- menu = await reportFromContextMenuRemove();
- info("Wait for the report panel");
- panelEl = await onceReportOpened;
-
- info("Wait for the report panel to be closed");
- await AbuseReportTestUtils.closeReportPanel(panelEl);
-
- menu.hidePopup();
-
- onceExtStarted = AddonTestUtils.promiseWebExtensionStartup(EXT_ID);
- addon.cancelUninstall();
- await onceExtStarted;
- });
-
- await addon.uninstall();
-});
-
-/*
- * Test report action hidden on non-supported extension types.
- */
-add_task(async function test_report_action_hidden_on_builtin_addons() {
- await openAboutAddons("theme");
- await AbuseReportTestUtils.assertReportActionHidden(
- gManagerWindow,
- DEFAULT_BUILTIN_THEME_ID
- );
- await closeAboutAddons();
-});
-
-add_task(async function test_report_action_hidden_on_system_addons() {
- await openAboutAddons("extension");
- await AbuseReportTestUtils.assertReportActionHidden(
- gManagerWindow,
- EXT_SYSTEM_ADDON_ID
- );
- await closeAboutAddons();
-});
-
-add_task(async function test_report_action_hidden_on_dictionary_addons() {
- await openAboutAddons("dictionary");
- await AbuseReportTestUtils.assertReportActionHidden(
- gManagerWindow,
- EXT_DICTIONARY_ADDON_ID
- );
- await closeAboutAddons();
-});
-
-add_task(async function test_report_action_hidden_on_langpack_addons() {
- await openAboutAddons("locale");
- await AbuseReportTestUtils.assertReportActionHidden(
- gManagerWindow,
- EXT_LANGPACK_ADDON_ID
- );
- await closeAboutAddons();
-});
-
-// This test verifies that triggering a report that would be immediately
-// cancelled (e.g. because abuse reports for that extension type are not
-// supported) the abuse report is being hidden as expected.
-add_task(async function test_report_hidden_on_report_unsupported_addontype() {
- await openAboutAddons();
-
- let onceCreateReportFailed = AbuseReportTestUtils.promiseMessageBars(1);
-
- AbuseReportTestUtils.triggerNewReport(EXT_UNSUPPORTED_TYPE_ADDON_ID, "menu");
-
- await onceCreateReportFailed;
-
- ok(!AbuseReporter.getOpenDialog(), "report dialog should not be open");
-
- await closeAboutAddons();
-});
-
-/*
- * Test regression fixes.
- */
-
-add_task(async function test_no_broken_suggestion_on_missing_supportURL() {
- const EXT_ID = "test-no-author@mochi.test";
- const extension = await installTestExtension(EXT_ID, "extension", {
- homepage_url: undefined,
- });
-
- const abuseReportEl = await AbuseReportTestUtils.openReport(EXT_ID);
-
- info("Select broken as the abuse reason");
- abuseReportEl.querySelector("#abuse-reason-broken").checked = true;
-
- let oncePanelUpdated = AbuseReportTestUtils.promiseReportUpdated(
- abuseReportEl,
- "submit"
- );
- await AbuseReportTestUtils.clickPanelButton(abuseReportEl._btnNext);
- await oncePanelUpdated;
-
- const suggestionEl = abuseReportEl.querySelector(
- "abuse-report-reason-suggestions"
- );
- is(suggestionEl.reason, "broken", "Got the expected suggestion element");
- ok(suggestionEl.hidden, "suggestion element should be empty");
-
- await closeAboutAddons();
- await extension.unload();
-});
-
-// This test verify that the abuse report panel is opening the
-// author link using a null triggeringPrincipal.
-add_task(async function test_abusereport_open_author_url() {
- const abuseReportEl = await AbuseReportTestUtils.openReport(
- EXT_WITH_PRIVILEGED_URL_ID
- );
-
- const authorLink = abuseReportEl._linkAddonAuthor;
- ok(authorLink, "Got the author link element");
- is(
- authorLink.href,
- "about:config",
- "Got a privileged url in the link element"
- );
-
- SimpleTest.waitForExplicitFinish();
- let waitForConsole = new Promise(resolve => {
- SimpleTest.monitorConsole(resolve, [
- {
- message:
- // eslint-disable-next-line max-len
- /Security Error: Content at moz-nullprincipal:{.*} may not load or link to about:config/,
- },
- ]);
- });
-
- let tabSwitched = BrowserTestUtils.waitForEvent(gBrowser, "TabSwitchDone");
- authorLink.click();
- await tabSwitched;
-
- is(
- gBrowser.selectedBrowser.currentURI.spec,
- "about:blank",
- "Got about:blank loaded in the new tab"
- );
-
- SimpleTest.endMonitorConsole();
- await waitForConsole;
-
- BrowserTestUtils.removeTab(gBrowser.selectedTab);
- await closeAboutAddons();
-});
-
-add_task(async function test_no_report_checkbox_for_unsupported_addon_types() {
- async function test_report_checkbox_hidden(addon) {
- await openAboutAddons(addon.type);
-
- const addonCard = gManagerWindow.document.querySelector(
- `addon-list addon-card[addon-id="${addon.id}"]`
- );
- ok(addonCard, "Got the addon-card for the test extension");
-
- const removeButton = addonCard.querySelector("[action=remove]");
- ok(removeButton, "Got the remove action for the test extension");
-
- // Prepare the mocked prompt service.
- const promptService = mockPromptService();
- promptService.confirmEx = createPromptConfirmEx({
- remove: true,
- report: false,
- expectCheckboxHidden: true,
- });
-
- info("Click the report action and wait for the addon to be removed");
- const promiseCardRemoved = BrowserTestUtils.waitForEvent(
- addonCard.closest("addon-list"),
- "remove"
- );
- removeButton.click();
- await promiseCardRemoved;
-
- await closeAboutAddons();
- }
-
- const reportNotSupportedAddons = [
- {
- id: "fake-langpack-to-remove@mochi.test",
- name: "This is a fake langpack",
- version: "1.1",
- type: "locale",
- },
- {
- id: "fake-dictionary-to-remove@mochi.test",
- name: "This is a fake dictionary",
- version: "1.1",
- type: "dictionary",
- },
- ];
-
- AbuseReportTestUtils.createMockAddons(reportNotSupportedAddons);
-
- for (const { id } of reportNotSupportedAddons) {
- const addon = await AddonManager.getAddonByID(id);
- await test_report_checkbox_hidden(addon);
- }
-});
-
-add_task(async function test_author_hidden_when_missing() {
- const EXT_ID = "test-no-author@mochi.test";
- const extension = await installTestExtension(EXT_ID, "extension", {
- author: undefined,
- });
-
- const abuseReportEl = await AbuseReportTestUtils.openReport(EXT_ID);
-
- const addon = await AddonManager.getAddonByID(EXT_ID);
-
- ok(!addon.creator, "addon.creator should not be undefined");
- ok(
- abuseReportEl._addonAuthorContainer.hidden,
- "author container should be hidden"
- );
-
- await closeAboutAddons();
- await extension.unload();
-});
-
-// Verify addon.siteOrigin is used as a fallback when homepage_url/developer.url
-// or support url are missing.
-//
-// TODO(Bug 1789718): adapt to SitePermAddonProvider implementation.
-add_task(async function test_siteperm_siteorigin_fallback() {
- const SITEPERM_ADDON_ID = "webmidi-site-origin@mochi.test";
- const sitePermAddon = await installTestExtension(
- SITEPERM_ADDON_ID,
- "sitepermission-deprecated",
- {
- homepage_url: undefined,
- }
- );
-
- const abuseReportEl = await AbuseReportTestUtils.openReport(
- SITEPERM_ADDON_ID
- );
- const addon = await AddonManager.getAddonByID(SITEPERM_ADDON_ID);
-
- ok(addon.siteOrigin, "addon.siteOrigin should not be undefined");
- ok(!addon.supportURL, "addon.supportURL should not be set");
- ok(!addon.homepageURL, "addon.homepageURL should not be set");
- is(
- abuseReportEl.supportURL,
- addon.siteOrigin,
- "Got the expected support_url"
- );
-
- await closeAboutAddons();
- await sitePermAddon.unload();
-});
diff --git a/toolkit/mozapps/extensions/test/browser/browser_html_abuse_report_dialog.js b/toolkit/mozapps/extensions/test/browser/browser_html_abuse_report_dialog.js
deleted file mode 100644
index 1efb28add3..0000000000
--- a/toolkit/mozapps/extensions/test/browser/browser_html_abuse_report_dialog.js
+++ /dev/null
@@ -1,185 +0,0 @@
-/* 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/. */
-/* eslint max-len: ["error", 80] */
-
-loadTestSubscript("head_abuse_report.js");
-
-add_setup(async function () {
- // Make sure the integrated abuse report panel is the one enabled
- // while this test file runs (instead of the AMO hosted form).
- // NOTE: behaviors expected when amoFormEnabled is true are tested
- // in the separate browser_amo_abuse_report.js test file.
- await SpecialPowers.pushPrefEnv({
- set: [["extensions.abuseReport.amoFormEnabled", false]],
- });
- await AbuseReportTestUtils.setup();
-});
-
-/**
- * Test tasks specific to the abuse report opened in its own dialog window.
- */
-
-add_task(async function test_close_icon_button_hidden_when_dialog() {
- const addonId = "addon-to-report@mochi.test";
- const extension = await installTestExtension(addonId);
-
- const reportDialog = await AbuseReporter.openDialog(
- addonId,
- "menu",
- gBrowser.selectedBrowser
- );
- await AbuseReportTestUtils.promiseReportDialogRendered();
-
- const panelEl = await reportDialog.promiseReportPanel;
-
- let promiseClosedWindow = waitClosedWindow();
-
- EventUtils.synthesizeKey("VK_RETURN", {}, panelEl.ownerGlobal);
- AbuseReportTestUtils.triggerSubmit("fake-reason", "fake-message");
-
- await promiseClosedWindow;
- ok(
- await reportDialog.promiseReport,
- "expect the report to not be cancelled by pressing enter"
- );
-
- await extension.unload();
-});
-
-add_task(async function test_report_triggered_when_report_dialog_is_open() {
- const addonId = "addon-to-report@mochi.test";
- const extension = await installTestExtension(addonId);
-
- const reportDialog = await AbuseReporter.openDialog(
- addonId,
- "menu",
- gBrowser.selectedBrowser
- );
- await AbuseReportTestUtils.promiseReportDialogRendered();
-
- let promiseClosedWindow = waitClosedWindow();
-
- const reportDialog2 = await AbuseReporter.openDialog(
- addonId,
- "menu",
- gBrowser.selectedBrowser
- );
-
- await promiseClosedWindow;
-
- // Trigger the report submit and check that the second report is
- // resolved as expected.
- await AbuseReportTestUtils.promiseReportDialogRendered();
-
- ok(
- !reportDialog.window || reportDialog.window.closed,
- "expect the first dialog to be closed"
- );
- ok(!!reportDialog2.window, "expect the second dialog to be open");
-
- is(
- reportDialog2.window,
- AbuseReportTestUtils.getReportDialog(),
- "Got a report dialog as expected"
- );
-
- AbuseReportTestUtils.triggerSubmit("fake-reason", "fake-message");
-
- // promiseReport is resolved to undefined if the report has been
- // cancelled, otherwise it is resolved to a report object.
- ok(
- !(await reportDialog.promiseReport),
- "expect the first report to be cancelled"
- );
- ok(
- !!(await reportDialog2.promiseReport),
- "expect the second report to be resolved"
- );
-
- await extension.unload();
-});
-
-add_task(async function test_report_dialog_window_closed_by_user() {
- const addonId = "addon-to-report@mochi.test";
- const extension = await installTestExtension(addonId);
-
- const reportDialog = await AbuseReporter.openDialog(
- addonId,
- "menu",
- gBrowser.selectedBrowser
- );
- await AbuseReportTestUtils.promiseReportDialogRendered();
-
- let promiseClosedWindow = waitClosedWindow();
-
- reportDialog.close();
-
- await promiseClosedWindow;
-
- ok(
- !(await reportDialog.promiseReport),
- "expect promiseReport to be resolved as user cancelled"
- );
-
- await extension.unload();
-});
-
-add_task(async function test_amo_details_for_not_installed_addon() {
- const addonId = "not-installed-addon@mochi.test";
- const fakeAMODetails = {
- name: "fake name",
- current_version: { version: "1.0" },
- type: "extension",
- icon_url: "http://test.addons.org/asserts/fake-icon-url.png",
- homepage: "http://fake.url/homepage",
- support_url: "http://fake.url/support",
- authors: [
- { name: "author1", url: "http://fake.url/author1" },
- { name: "author2", url: "http://fake.url/author2" },
- ],
- is_recommended: true,
- };
-
- AbuseReportTestUtils.amoAddonDetailsMap.set(addonId, fakeAMODetails);
- registerCleanupFunction(() =>
- AbuseReportTestUtils.amoAddonDetailsMap.clear()
- );
-
- const reportDialog = await AbuseReporter.openDialog(
- addonId,
- "menu",
- gBrowser.selectedBrowser
- );
-
- const reportEl = await reportDialog.promiseReportPanel;
-
- // Assert that the panel has been able to retrieve from AMO
- // all the addon details needed to render the panel correctly.
- is(reportEl.addonId, addonId, "Got the expected addonId");
- is(reportEl.addonName, fakeAMODetails.name, "Got the expected addon name");
- is(reportEl.addonType, fakeAMODetails.type, "Got the expected addon type");
- is(
- reportEl.authorName,
- fakeAMODetails.authors[0].name,
- "Got the first author name as expected"
- );
- is(
- reportEl.authorURL,
- fakeAMODetails.authors[0].url,
- "Got the first author url as expected"
- );
- is(reportEl.iconURL, fakeAMODetails.icon_url, "Got the expected icon url");
- is(
- reportEl.supportURL,
- fakeAMODetails.support_url,
- "Got the expected support url"
- );
- is(
- reportEl.homepageURL,
- fakeAMODetails.homepage,
- "Got the expected homepage url"
- );
-
- reportDialog.close();
-});
diff --git a/toolkit/mozapps/extensions/test/browser/browser_html_detail_permissions.js b/toolkit/mozapps/extensions/test/browser/browser_html_detail_permissions.js
index 32543f3bc9..130375020d 100644
--- a/toolkit/mozapps/extensions/test/browser/browser_html_detail_permissions.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_html_detail_permissions.js
@@ -419,7 +419,11 @@ async function runTest(options) {
}
}
-async function testPermissionsView({ manifestV3enabled, manifest_version }) {
+async function testPermissionsView({
+ manifestV3enabled,
+ manifest_version,
+ expectGranted,
+}) {
await SpecialPowers.pushPrefEnv({
set: [["extensions.manifestV3.enabled", manifestV3enabled]],
});
@@ -438,7 +442,16 @@ async function testPermissionsView({ manifestV3enabled, manifest_version }) {
extension: extensions["addon1@mochi.test"],
permissions: ["<all_urls>", "tabs", "webNavigation"],
});
- } else {
+ }
+ if (manifest_version >= 3 && expectGranted) {
+ await runTest({
+ extension: extensions["addon1@mochi.test"],
+ permissions: ["tabs", "webNavigation"],
+ optional_permissions: ["<all_urls>"],
+ optional_enabled: ["<all_urls>"],
+ });
+ }
+ if (manifest_version >= 3 && !expectGranted) {
await runTest({
extension: extensions["addon1@mochi.test"],
permissions: ["tabs", "webNavigation"],
@@ -544,8 +557,28 @@ add_task(async function testPermissionsView_MV2_manifestV3enabled() {
await testPermissionsView({ manifestV3enabled: true, manifest_version: 2 });
});
+add_task(async function testPermissionsView_MV3_noInstallPrompt() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["extensions.originControls.grantByDefault", false]],
+ });
+ await testPermissionsView({
+ manifestV3enabled: true,
+ manifest_version: 3,
+ expectGranted: false,
+ });
+ await SpecialPowers.popPrefEnv();
+});
+
add_task(async function testPermissionsView_MV3() {
- await testPermissionsView({ manifestV3enabled: true, manifest_version: 3 });
+ await SpecialPowers.pushPrefEnv({
+ set: [["extensions.originControls.grantByDefault", true]],
+ });
+ await testPermissionsView({
+ manifestV3enabled: true,
+ manifest_version: 3,
+ expectGranted: true,
+ });
+ await SpecialPowers.popPrefEnv();
});
add_task(async function testPermissionsViewStates() {
@@ -623,7 +656,10 @@ add_task(async function testPermissionsViewStates() {
add_task(async function testAllUrlsNotGrantedUnconditionally_MV3() {
await SpecialPowers.pushPrefEnv({
- set: [["extensions.manifestV3.enabled", true]],
+ set: [
+ ["extensions.manifestV3.enabled", true],
+ ["extensions.originControls.grantByDefault", false],
+ ],
});
const extension = ExtensionTestUtils.loadExtension({
diff --git a/toolkit/mozapps/extensions/test/browser/browser_html_detail_view.js b/toolkit/mozapps/extensions/test/browser/browser_html_detail_view.js
index 76e7f2b255..8930d6dede 100644
--- a/toolkit/mozapps/extensions/test/browser/browser_html_detail_view.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_html_detail_view.js
@@ -1260,7 +1260,7 @@ add_task(async function testGoBackButtonIsDisabledWhenHistoryIsEmpty() {
// When we have a fresh new tab, `about:addons` is opened in it.
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, null);
// Simulate a click on "Manage extension" from a context menu.
- let win = await BrowserOpenAddonsMgr(viewID);
+ let win = await BrowserAddonUI.openAddonsMgr(viewID);
await assertBackButtonIsDisabled(win);
BrowserTestUtils.removeTab(tab);
@@ -1288,7 +1288,7 @@ add_task(async function testGoBackButtonIsDisabledWhenHistoryIsEmptyInNewTab() {
true
);
// Simulate a click on "Manage extension" from a context menu.
- let win = await BrowserOpenAddonsMgr(viewID);
+ let win = await BrowserAddonUI.openAddonsMgr(viewID);
let addonsTab = await addonsTabLoaded;
await assertBackButtonIsDisabled(win);
@@ -1309,7 +1309,7 @@ add_task(async function testGoBackButtonIsDisabledAfterBrowserBackButton() {
// When we have a fresh new tab, `about:addons` is opened in it.
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, null);
// Simulate a click on "Manage extension" from a context menu.
- let win = await BrowserOpenAddonsMgr(viewID);
+ let win = await BrowserAddonUI.openAddonsMgr(viewID);
await assertBackButtonIsDisabled(win);
// Navigate to the extensions list.
diff --git a/toolkit/mozapps/extensions/test/browser/browser_html_discover_view.js b/toolkit/mozapps/extensions/test/browser/browser_html_discover_view.js
index 30cb45dc60..fdb0fabfd4 100644
--- a/toolkit/mozapps/extensions/test/browser/browser_html_discover_view.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_html_discover_view.js
@@ -653,11 +653,16 @@ add_task(async function checkDiscopaneNotice() {
"moz-message-bar.discopane-notice"
);
ok(messageBar, "Recommended notice should exist in extensions view");
+ is(
+ messageBar.getAttribute("role"),
+ "alert",
+ "Recommended notice is an alert"
+ );
await switchToDiscoView(win);
messageBar = win.document.querySelector("moz-message-bar.discopane-notice");
ok(messageBar, "Recommended notice should exist in disco view");
- messageBar.closeButtonEl.click();
+ messageBar.closeButton.click();
messageBar = win.document.querySelector("moz-message-bar.discopane-notice");
ok(!messageBar, "Recommended notice should not exist in disco view");
await switchToNonDiscoView(win);
diff --git a/toolkit/mozapps/extensions/test/browser/browser_html_message_bar.js b/toolkit/mozapps/extensions/test/browser/browser_html_message_bar.js
deleted file mode 100644
index b60baf8799..0000000000
--- a/toolkit/mozapps/extensions/test/browser/browser_html_message_bar.js
+++ /dev/null
@@ -1,185 +0,0 @@
-/* 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/. */
-
-/* eslint max-len: ["error", 80] */
-
-let htmlAboutAddonsWindow;
-
-const HTML_NS = "http://www.w3.org/1999/xhtml";
-
-function clickElement(el) {
- el.dispatchEvent(new CustomEvent("click"));
-}
-
-function createMessageBar(messageBarStack, { attrs, children, onclose } = {}) {
- const win = messageBarStack.ownerGlobal;
- const messageBar = win.document.createElementNS(HTML_NS, "message-bar");
- if (attrs) {
- for (const [k, v] of Object.entries(attrs)) {
- messageBar.setAttribute(k, v);
- }
- }
- if (children) {
- if (Array.isArray(children)) {
- messageBar.append(...children);
- } else {
- messageBar.append(children);
- }
- }
- messageBar.addEventListener("message-bar:close", onclose, { once: true });
- messageBarStack.append(messageBar);
- return messageBar;
-}
-
-add_setup(async function () {
- htmlAboutAddonsWindow = await loadInitialView("extension");
- registerCleanupFunction(() => closeView(htmlAboutAddonsWindow));
-});
-
-add_task(async function test_message_bar_stack() {
- const win = htmlAboutAddonsWindow;
-
- let messageBarStack = win.document.getElementById("abuse-reports-messages");
-
- ok(messageBarStack, "Got a message-bar-stack in HTML about:addons page");
-
- is(
- messageBarStack.maxMessageBarCount,
- 3,
- "Got the expected max-message-bar-count property"
- );
-
- is(
- messageBarStack.childElementCount,
- 0,
- "message-bar-stack is initially empty"
- );
-});
-
-add_task(async function test_create_message_bar_create_and_onclose() {
- const win = htmlAboutAddonsWindow;
- const messageBarStack = win.document.getElementById("abuse-reports-messages");
-
- let messageEl = win.document.createElementNS(HTML_NS, "span");
- messageEl.textContent = "A message bar text";
- let buttonEl = win.document.createElementNS(HTML_NS, "button");
- buttonEl.textContent = "An action button";
-
- let messageBar;
- let onceMessageBarClosed = new Promise(resolve => {
- messageBar = createMessageBar(messageBarStack, {
- children: [messageEl, buttonEl],
- onclose: resolve,
- });
- });
-
- is(
- messageBarStack.childElementCount,
- 1,
- "message-bar-stack has a child element"
- );
- is(
- messageBarStack.firstElementChild,
- messageBar,
- "newly created message-bar added as message-bar-stack child element"
- );
-
- const slot = messageBar.shadowRoot.querySelector("slot");
- is(
- slot.assignedNodes()[0],
- messageEl,
- "Got the expected span element assigned to the message-bar slot"
- );
- is(
- slot.assignedNodes()[1],
- buttonEl,
- "Got the expected button element assigned to the message-bar slot"
- );
-
- let dismissed = BrowserTestUtils.waitForEvent(
- messageBar,
- "message-bar:user-dismissed"
- );
- info("Click the close icon on the newly created message-bar");
- clickElement(messageBar.closeButton);
- await dismissed;
-
- info("Expect the onclose function to be called");
- await onceMessageBarClosed;
-
- is(
- messageBarStack.childElementCount,
- 0,
- "message-bar-stack has no child elements"
- );
-});
-
-add_task(async function test_max_message_bar_count() {
- const win = htmlAboutAddonsWindow;
- const messageBarStack = win.document.getElementById("abuse-reports-messages");
-
- info("Create a new message-bar");
- let messageElement = document.createElementNS(HTML_NS, "span");
- messageElement = "message bar label";
-
- let onceMessageBarClosed = new Promise(resolve => {
- createMessageBar(messageBarStack, {
- children: messageElement,
- onclose: resolve,
- });
- });
-
- is(
- messageBarStack.childElementCount,
- 1,
- "message-bar-stack has the expected number of children"
- );
-
- info("Create 3 more message bars");
- const allBarsPromises = [];
- for (let i = 2; i <= 4; i++) {
- allBarsPromises.push(
- new Promise(resolve => {
- createMessageBar(messageBarStack, {
- attrs: { dismissable: "" },
- children: [messageElement, i],
- onclose: resolve,
- });
- })
- );
- }
-
- info("Expect first message-bar to closed automatically");
- await onceMessageBarClosed;
-
- is(
- messageBarStack.childElementCount,
- 3,
- "message-bar-stack has the expected number of children"
- );
-
- info("Click on close icon for the second message-bar");
- clickElement(messageBarStack.firstElementChild.closeButton);
-
- info("Expect the second message-bar to be closed");
- await allBarsPromises[0];
-
- is(
- messageBarStack.childElementCount,
- 2,
- "message-bar-stack has the expected number of children"
- );
-
- info("Clear the entire message-bar-stack content");
- messageBarStack.textContent = "";
-
- info("Expect all the created message-bar to be closed automatically");
- await Promise.all(allBarsPromises);
-
- is(
- messageBarStack.childElementCount,
- 0,
- "message-bar-stack has no child elements"
- );
-});
diff --git a/toolkit/mozapps/extensions/test/browser/browser_html_options_ui_dark_theme.js b/toolkit/mozapps/extensions/test/browser/browser_html_options_ui_dark_theme.js
new file mode 100644
index 0000000000..9261fa0a7e
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/browser/browser_html_options_ui_dark_theme.js
@@ -0,0 +1,173 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { AddonTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/AddonTestUtils.sys.mjs"
+);
+
+AddonTestUtils.initMochitest(this);
+
+const LIGHT_SCHEME_BG = "rgb(255, 255, 255)";
+const LIGHT_SCHEME_FG = "rgb(0, 0, 0)";
+
+// "browser.display.background_color.dark" pref value ("#1C1B22") maps to:
+const DARK_SCHEME_BG = "rgb(28, 27, 34)";
+const DARK_SCHEME_FG = "rgb(251, 251, 254)";
+
+async function getColorsForOptionsUI({ browser_style, open_in_tab }) {
+ let extension = ExtensionTestUtils.loadExtension({
+ useAddonManager: "temporary",
+ manifest: {
+ options_ui: {
+ browser_style,
+ page: "options.html",
+ open_in_tab,
+ },
+ },
+ background() {
+ browser.test.onMessage.addListener(msg => {
+ browser.test.assertEq("openOptionsPage", msg, "expect openOptionsPage");
+ browser.runtime.openOptionsPage();
+ });
+ },
+ files: {
+ "options.html": `<style>:root { color-scheme: dark light; }</style>
+ <script src="options.js"></script>`,
+ "options.js": () => {
+ window.onload = () => {
+ browser.test.sendMessage("options_ui_opened");
+ };
+ },
+ },
+ });
+
+ await extension.startup();
+ extension.sendMessage("openOptionsPage");
+ await extension.awaitMessage("options_ui_opened");
+
+ const tab = gBrowser.selectedTab;
+ let optionsBrowser;
+ if (open_in_tab) {
+ optionsBrowser = tab.linkedBrowser;
+ is(
+ optionsBrowser.currentURI.spec,
+ `moz-extension://${extension.uuid}/options.html`,
+ "With open_in_tab=true, should open options.html in tab"
+ );
+ } else {
+ // When not opening in a new tab, the inline options page is used.
+ is(
+ tab.linkedBrowser.currentURI.spec,
+ "about:addons",
+ "Without open_in_tab, should open about:addons"
+ );
+ optionsBrowser = tab.linkedBrowser.contentDocument.getElementById(
+ "addon-inline-options"
+ );
+ is(
+ optionsBrowser.currentURI.spec,
+ `moz-extension://${extension.uuid}/options.html`,
+ "Found options.html in inline options browser"
+ );
+ }
+
+ let colors = await SpecialPowers.spawn(optionsBrowser, [], () => {
+ let style = content.getComputedStyle(content.document.body);
+ // Note: cannot use style.backgroundColor because it defaults to
+ // "transparent" (aka rgba(0, 0, 0, 0)) which is meaningless.
+ // So we have to use windowUtils.canvasBackgroundColor instead.
+ return {
+ bgColor: content.windowUtils.canvasBackgroundColor,
+ fgColor: style.color,
+ };
+ });
+
+ if (colors.bgColor === "rgba(0, 0, 0, 0)") {
+ // windowUtils.canvasBackgroundColor may still report a "transparent"
+ // background color when the options page is rendered inline in a <browser>
+ // at about:addons. In that case, the background color of the container
+ // element (i.e. the <browser>) is used to render the contents.
+ Assert.ok(!open_in_tab, "Background only transparent without open_in_tab");
+ let style = optionsBrowser.ownerGlobal.getComputedStyle(optionsBrowser);
+ colors.bgColor = style.backgroundColor;
+ }
+
+ BrowserTestUtils.removeTab(tab);
+
+ await extension.unload();
+ return colors;
+}
+
+add_setup(async () => {
+ // The test calls openOptionsPage, which may end up re-using an existing blank
+ // tab. Upon closing that, the browser window of the test would close and the
+ // test would get stuck. To avoid that, make sure that there is a dummy tab
+ // around that keeps the window open.
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "data:,");
+ registerCleanupFunction(() => {
+ BrowserTestUtils.removeTab(tab);
+ });
+});
+
+add_task(async function options_ui_open_in_tab_light() {
+ await SpecialPowers.pushPrefEnv({ set: [["ui.systemUsesDarkTheme", 0]] });
+ // Note: browser_style:true should be no-op when open_in_tab:true.
+ // Therefore the result should be equivalent to the color of a normal web
+ // page, instead of options_ui_inline_light.
+ Assert.deepEqual(
+ await getColorsForOptionsUI({ browser_style: true, open_in_tab: true }),
+ { bgColor: LIGHT_SCHEME_BG, fgColor: LIGHT_SCHEME_FG }
+ );
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function options_ui_open_in_tab_dark() {
+ await SpecialPowers.pushPrefEnv({ set: [["ui.systemUsesDarkTheme", 1]] });
+ // Note: browser_style:true should be no-op when open_in_tab:true.
+ // Therefore the result should be equivalent to the color of a normal web
+ // page, instead of options_ui_inline_dark.
+ Assert.deepEqual(
+ await getColorsForOptionsUI({ browser_style: true, open_in_tab: true }),
+ { bgColor: DARK_SCHEME_BG, fgColor: DARK_SCHEME_FG }
+ );
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function options_ui_light() {
+ await SpecialPowers.pushPrefEnv({ set: [["ui.systemUsesDarkTheme", 0]] });
+ Assert.deepEqual(
+ await getColorsForOptionsUI({ browser_style: false, open_in_tab: false }),
+ { bgColor: LIGHT_SCHEME_BG, fgColor: LIGHT_SCHEME_FG }
+ );
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function options_ui_dark() {
+ await SpecialPowers.pushPrefEnv({ set: [["ui.systemUsesDarkTheme", 1]] });
+ Assert.deepEqual(
+ await getColorsForOptionsUI({ browser_style: false, open_in_tab: false }),
+ { bgColor: DARK_SCHEME_BG, fgColor: DARK_SCHEME_FG }
+ );
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function options_ui_browser_style_true_light() {
+ await SpecialPowers.pushPrefEnv({ set: [["ui.systemUsesDarkTheme", 0]] });
+ Assert.deepEqual(
+ await getColorsForOptionsUI({ browser_style: true, open_in_tab: false }),
+ // rgb(34, 36, 38) = color: #222426 from extension.css
+ { bgColor: LIGHT_SCHEME_BG, fgColor: "rgb(34, 36, 38)" }
+ );
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function options_ui_browser_style_true_dark() {
+ await SpecialPowers.pushPrefEnv({ set: [["ui.systemUsesDarkTheme", 1]] });
+ Assert.deepEqual(
+ await getColorsForOptionsUI({ browser_style: true, open_in_tab: false }),
+ { bgColor: DARK_SCHEME_BG, fgColor: DARK_SCHEME_FG }
+ );
+ await SpecialPowers.popPrefEnv();
+});
diff --git a/toolkit/mozapps/extensions/test/browser/browser_html_scroll_restoration.js b/toolkit/mozapps/extensions/test/browser/browser_html_scroll_restoration.js
index e4d88bc19a..76471007ec 100644
--- a/toolkit/mozapps/extensions/test/browser/browser_html_scroll_restoration.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_html_scroll_restoration.js
@@ -91,11 +91,15 @@ async function waitForStableLayout(win) {
}
function isLayoutStable(win) {
- // <message-bar> elements may affect the layout of a page, and therefore we
- // should check whether its embedded style sheet has finished loading.
- for (let bar of win.document.querySelectorAll("message-bar")) {
- // Check for the existence of a CSS property from message-bar.css.
- if (!win.getComputedStyle(bar).getPropertyValue("--message-bar-icon-url")) {
+ // <moz-message-bar> elements may affect the layout of a page, and therefore
+ // we should check whether its embedded style sheet has finished loading.
+ for (let bar of win.document.querySelectorAll("moz-message-bar")) {
+ // Check for the existence of a CSS property from moz-message-bar.css.
+ if (
+ !win
+ .getComputedStyle(bar)
+ .getPropertyValue("--message-bar-background-color")
+ ) {
return false;
}
}
diff --git a/toolkit/mozapps/extensions/test/browser/browser_webapi_abuse_report.js b/toolkit/mozapps/extensions/test/browser/browser_webapi_abuse_report.js
deleted file mode 100644
index b9ea0f6a93..0000000000
--- a/toolkit/mozapps/extensions/test/browser/browser_webapi_abuse_report.js
+++ /dev/null
@@ -1,375 +0,0 @@
-/* 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/. */
-/* eslint max-len: ["error", 80] */
-
-loadTestSubscript("head_abuse_report.js");
-
-const TESTPAGE = `${SECURE_TESTROOT}webapi_checkavailable.html`;
-const TELEMETRY_EVENTS_FILTERS = {
- category: "addonsManager",
- method: "report",
-};
-const REPORT_PROP_NAMES = [
- "addon",
- "addon_signature",
- "reason",
- "message",
- "report_entry_point",
-];
-
-function getObjectProps(obj, propNames) {
- const res = {};
- for (const k of propNames) {
- res[k] = obj[k];
- }
- return res;
-}
-
-async function assertSubmittedReport(expectedReportProps) {
- let reportSubmitted;
- const onReportSubmitted = AbuseReportTestUtils.promiseReportSubmitHandled(
- ({ data, request, response }) => {
- reportSubmitted = JSON.parse(data);
- handleSubmitRequest({ request, response });
- }
- );
-
- let panelEl = await AbuseReportTestUtils.promiseReportDialogRendered();
-
- let promiseWinClosed = waitClosedWindow();
- let promisePanelUpdated = AbuseReportTestUtils.promiseReportUpdated(
- panelEl,
- "submit"
- );
- panelEl._form.elements.reason.value = expectedReportProps.reason;
- AbuseReportTestUtils.clickPanelButton(panelEl._btnNext);
- await promisePanelUpdated;
-
- panelEl._form.elements.message.value = expectedReportProps.message;
- // Reset the timestamp of the last report between tests.
- AbuseReporter._lastReportTimestamp = null;
- AbuseReportTestUtils.clickPanelButton(panelEl._btnSubmit);
- await Promise.all([onReportSubmitted, promiseWinClosed]);
-
- ok(!panelEl.ownerGlobal, "Report dialog window is closed");
- Assert.deepEqual(
- getObjectProps(reportSubmitted, REPORT_PROP_NAMES),
- expectedReportProps,
- "Got the expected report data submitted"
- );
-}
-
-add_setup(async function () {
- await AbuseReportTestUtils.setup();
-
- await SpecialPowers.pushPrefEnv({
- set: [
- ["extensions.webapi.testing", true],
- ["extensions.abuseReport.amWebAPI.enabled", true],
- // Make sure the integrated abuse report panel is the one enabled
- // while this test file runs (instead of the AMO hosted form).
- // NOTE: behaviors expected when amoFormEnabled is true are tested
- // in the separate browser_amo_abuse_report.js test file.
- ["extensions.abuseReport.amoFormEnabled", false],
- ],
- });
-});
-
-add_task(async function test_report_installed_addon_cancelled() {
- Services.telemetry.clearEvents();
-
- await BrowserTestUtils.withNewTab(TESTPAGE, async browser => {
- const extension = await installTestExtension(ADDON_ID);
-
- let reportEnabled = await SpecialPowers.spawn(browser, [], () => {
- return content.navigator.mozAddonManager.abuseReportPanelEnabled;
- });
-
- is(reportEnabled, true, "Expect abuseReportPanelEnabled to be true");
-
- info("Test reportAbuse result on user cancelled report");
-
- let promiseNewWindow = waitForNewWindow();
- let promiseWebAPIResult = SpecialPowers.spawn(
- browser,
- [ADDON_ID],
- addonId => content.navigator.mozAddonManager.reportAbuse(addonId)
- );
-
- let win = await promiseNewWindow;
- is(win, AbuseReportTestUtils.getReportDialog(), "Got the report dialog");
-
- let panelEl = await AbuseReportTestUtils.promiseReportDialogRendered();
-
- let promiseWinClosed = waitClosedWindow();
- AbuseReportTestUtils.clickPanelButton(panelEl._btnCancel);
- let reportResult = await promiseWebAPIResult;
- is(
- reportResult,
- false,
- "Expect reportAbuse to resolve to false on user cancelled report"
- );
- await promiseWinClosed;
- ok(!panelEl.ownerGlobal, "Report dialog window is closed");
-
- await extension.unload();
- });
-
- // Expect no telemetry events collected for user cancelled reports.
- TelemetryTestUtils.assertEvents([], TELEMETRY_EVENTS_FILTERS);
-});
-
-add_task(async function test_report_installed_addon_submitted() {
- Services.telemetry.clearEvents();
-
- await BrowserTestUtils.withNewTab(TESTPAGE, async browser => {
- const extension = await installTestExtension(ADDON_ID);
-
- let promiseNewWindow = waitForNewWindow();
- let promiseWebAPIResult = SpecialPowers.spawn(browser, [ADDON_ID], id =>
- content.navigator.mozAddonManager.reportAbuse(id)
- );
- let win = await promiseNewWindow;
- is(win, AbuseReportTestUtils.getReportDialog(), "Got the report dialog");
-
- await assertSubmittedReport({
- addon: ADDON_ID,
- addon_signature: "missing",
- message: "fake report message",
- reason: "unwanted",
- report_entry_point: "amo",
- });
-
- let reportResult = await promiseWebAPIResult;
- is(
- reportResult,
- true,
- "Expect reportAbuse to resolve to false on user cancelled report"
- );
-
- await extension.unload();
- });
-
- TelemetryTestUtils.assertEvents(
- [
- {
- object: "amo",
- value: ADDON_ID,
- extra: { addon_type: "extension" },
- },
- ],
- TELEMETRY_EVENTS_FILTERS
- );
-});
-
-add_task(async function test_report_unknown_not_installed_addon() {
- const addonId = "unknown-addon@mochi.test";
- Services.telemetry.clearEvents();
-
- await BrowserTestUtils.withNewTab(TESTPAGE, async browser => {
- let promiseWebAPIResult = SpecialPowers.spawn(browser, [addonId], id =>
- content.navigator.mozAddonManager.reportAbuse(id).catch(err => {
- return { name: err.name, message: err.message };
- })
- );
-
- await Assert.deepEqual(
- await promiseWebAPIResult,
- { name: "Error", message: "Error creating abuse report" },
- "Got the expected rejected error on reporting unknown addon"
- );
-
- ok(!AbuseReportTestUtils.getReportDialog(), "No report dialog is open");
- });
-
- TelemetryTestUtils.assertEvents(
- [
- {
- object: "amo",
- value: addonId,
- extra: { error_type: "ERROR_AMODETAILS_NOTFOUND" },
- },
- {
- object: "amo",
- value: addonId,
- extra: { error_type: "ERROR_ADDON_NOTFOUND" },
- },
- ],
- TELEMETRY_EVENTS_FILTERS
- );
-});
-
-add_task(async function test_report_not_installed_addon() {
- const addonId = "not-installed-addon@mochi.test";
- Services.telemetry.clearEvents();
-
- await BrowserTestUtils.withNewTab(TESTPAGE, async browser => {
- const fakeAMODetails = {
- name: "fake name",
- current_version: { version: "1.0" },
- type: "extension",
- icon_url: "http://test.addons.org/asserts/fake-icon-url.png",
- homepage: "http://fake.url/homepage",
- authors: [{ name: "author1", url: "http://fake.url/author1" }],
- is_recommended: false,
- };
-
- AbuseReportTestUtils.amoAddonDetailsMap.set(addonId, fakeAMODetails);
- registerCleanupFunction(() =>
- AbuseReportTestUtils.amoAddonDetailsMap.clear()
- );
-
- let promiseNewWindow = waitForNewWindow();
-
- let promiseWebAPIResult = SpecialPowers.spawn(browser, [addonId], id =>
- content.navigator.mozAddonManager.reportAbuse(id)
- );
- let win = await promiseNewWindow;
- is(win, AbuseReportTestUtils.getReportDialog(), "Got the report dialog");
-
- await assertSubmittedReport({
- addon: addonId,
- addon_signature: "unknown",
- message: "fake report message",
- reason: "other",
- report_entry_point: "amo",
- });
-
- let reportResult = await promiseWebAPIResult;
- is(
- reportResult,
- true,
- "Expect reportAbuse to resolve to true on submitted report"
- );
- });
-
- TelemetryTestUtils.assertEvents(
- [
- {
- object: "amo",
- value: addonId,
- extra: { addon_type: "extension" },
- },
- ],
- TELEMETRY_EVENTS_FILTERS
- );
-});
-
-add_task(async function test_amo_report_on_report_already_inprogress() {
- const extension = await installTestExtension(ADDON_ID);
- const reportDialog = await AbuseReporter.openDialog(
- ADDON_ID,
- "menu",
- gBrowser.selectedBrowser
- );
- await AbuseReportTestUtils.promiseReportDialogRendered();
- ok(reportDialog.window, "Got an open report dialog");
-
- let promiseWinClosed = waitClosedWindow();
-
- await BrowserTestUtils.withNewTab(TESTPAGE, async browser => {
- const promiseAMOResult = SpecialPowers.spawn(browser, [ADDON_ID], id =>
- content.navigator.mozAddonManager.reportAbuse(id)
- );
-
- await promiseWinClosed;
- ok(reportDialog.window.closed, "previous report dialog should be closed");
-
- is(
- await reportDialog.promiseAMOResult,
- undefined,
- "old report cancelled after AMO called mozAddonManager.reportAbuse"
- );
-
- const panelEl = await AbuseReportTestUtils.promiseReportDialogRendered();
-
- const { report } = AbuseReportTestUtils.getReportDialogParams();
- Assert.deepEqual(
- {
- reportEntryPoint: report.reportEntryPoint,
- addonId: report.addon.id,
- },
- {
- reportEntryPoint: "amo",
- addonId: ADDON_ID,
- },
- "Got the expected report from the opened report dialog"
- );
-
- promiseWinClosed = waitClosedWindow();
- AbuseReportTestUtils.clickPanelButton(panelEl._btnCancel);
- await promiseWinClosed;
-
- is(
- await promiseAMOResult,
- false,
- "AMO report request resolved to false on cancel button clicked"
- );
- });
-
- await extension.unload();
-});
-
-add_task(async function test_reject_on_unsupported_addon_types() {
- const addonId = "not-supported-addon-type@mochi.test";
-
- await BrowserTestUtils.withNewTab(TESTPAGE, async browser => {
- const fakeAMODetails = {
- name: "fake name",
- current_version: { version: "1.0" },
- type: "fake-unsupported-addon-type",
- };
-
- AbuseReportTestUtils.amoAddonDetailsMap.set(addonId, fakeAMODetails);
- registerCleanupFunction(() =>
- AbuseReportTestUtils.amoAddonDetailsMap.clear()
- );
-
- let webAPIResult = await SpecialPowers.spawn(browser, [addonId], id =>
- content.navigator.mozAddonManager.reportAbuse(id).then(
- res => ({ gotRejection: false, result: res }),
- err => ({ gotRejection: true, message: err.message })
- )
- );
-
- Assert.deepEqual(
- webAPIResult,
- { gotRejection: true, message: "Error creating abuse report" },
- "Got the expected rejection from mozAddonManager.reportAbuse"
- );
- });
-});
-
-add_task(async function test_report_on_disabled_webapi() {
- await SpecialPowers.pushPrefEnv({
- set: [["extensions.abuseReport.amWebAPI.enabled", false]],
- });
-
- await BrowserTestUtils.withNewTab(TESTPAGE, async browser => {
- let reportEnabled = await SpecialPowers.spawn(browser, [], () => {
- return content.navigator.mozAddonManager.abuseReportPanelEnabled;
- });
-
- is(reportEnabled, false, "Expect abuseReportPanelEnabled to be false");
-
- info("Test reportAbuse result on report webAPI disabled");
-
- let promiseWebAPIResult = SpecialPowers.spawn(
- browser,
- ["an-addon@mochi.test"],
- addonId =>
- content.navigator.mozAddonManager.reportAbuse(addonId).catch(err => {
- return { name: err.name, message: err.message };
- })
- );
-
- Assert.deepEqual(
- await promiseWebAPIResult,
- { name: "Error", message: "amWebAPI reportAbuse not supported" },
- "Got the expected rejected error"
- );
- });
-
- await SpecialPowers.popPrefEnv();
-});
diff --git a/toolkit/mozapps/extensions/test/browser/head_abuse_report.js b/toolkit/mozapps/extensions/test/browser/head_abuse_report.js
index 78c9206e0a..173f6ab7ea 100644
--- a/toolkit/mozapps/extensions/test/browser/head_abuse_report.js
+++ b/toolkit/mozapps/extensions/test/browser/head_abuse_report.js
@@ -3,35 +3,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* eslint max-len: ["error", 80] */
-/* exported installTestExtension, addCommonAbuseReportTestTasks,
- * createPromptConfirmEx, DEFAULT_BUILTIN_THEME_ID,
- * gManagerWindow, handleSubmitRequest, makeWidgetId,
- * waitForNewWindow, waitClosedWindow, AbuseReporter,
- * AbuseReporterTestUtils, AddonTestUtils
+/* exported AbuseReportTestUtils, openAboutAddons, closeAboutAddons,
+ * gManagerWindow
*/
/* global MockProvider, loadInitialView, closeView */
-const { AbuseReporter } = ChromeUtils.importESModule(
- "resource://gre/modules/AbuseReporter.sys.mjs"
-);
const { AddonTestUtils } = ChromeUtils.importESModule(
"resource://testing-common/AddonTestUtils.sys.mjs"
);
-const { ExtensionCommon } = ChromeUtils.importESModule(
- "resource://gre/modules/ExtensionCommon.sys.mjs"
-);
-const { makeWidgetId } = ExtensionCommon;
-
-const ADDON_ID = "test-extension-to-report@mochi.test";
-const REPORT_ENTRY_POINT = "menu";
-const BASE_TEST_MANIFEST = {
- name: "Fake extension to report",
- author: "Fake author",
- homepage_url: "https://fake.extension.url/",
-};
-const DEFAULT_BUILTIN_THEME_ID = "default-theme@mozilla.org";
const EXT_DICTIONARY_ADDON_ID = "fake-dictionary@mochi.test";
const EXT_LANGPACK_ADDON_ID = "fake-langpack@mochi.test";
const EXT_WITH_PRIVILEGED_URL_ID = "ext-with-privileged-url@mochi.test";
@@ -54,110 +35,6 @@ async function closeAboutAddons() {
}
}
-function waitForNewWindow() {
- return new Promise(resolve => {
- let listener = win => {
- Services.obs.removeObserver(listener, "toplevel-window-ready");
- resolve(win);
- };
-
- Services.obs.addObserver(listener, "toplevel-window-ready");
- });
-}
-
-function waitClosedWindow(win) {
- return new Promise(resolve => {
- function onWindowClosed() {
- if (win && !win.closed) {
- // If a specific window reference has been passed, then check
- // that the window is closed before resolving the promise.
- return;
- }
- Services.obs.removeObserver(onWindowClosed, "xul-window-destroyed");
- resolve();
- }
- Services.obs.addObserver(onWindowClosed, "xul-window-destroyed");
- });
-}
-
-async function installTestExtension(
- id = ADDON_ID,
- type = "extension",
- manifest = {}
-) {
- let additionalProps = {
- icons: {
- 32: "test-icon.png",
- },
- };
-
- switch (type) {
- case "theme":
- additionalProps = {
- ...additionalProps,
- theme: {
- colors: {
- frame: "#a14040",
- tab_background_text: "#fac96e",
- },
- },
- };
- break;
-
- // TODO(Bug 1789718): Remove after the deprecated XPIProvider-based
- // implementation is also removed.
- case "sitepermission-deprecated":
- additionalProps = {
- name: "WebMIDI test addon for https://mochi.test",
- install_origins: ["https://mochi.test"],
- site_permissions: ["midi"],
- };
- break;
- case "extension":
- break;
- default:
- throw new Error(`Unexpected addon type: ${type}`);
- }
-
- const extensionOpts = {
- manifest: {
- ...BASE_TEST_MANIFEST,
- ...additionalProps,
- ...manifest,
- browser_specific_settings: { gecko: { id } },
- },
- useAddonManager: "temporary",
- };
-
- // TODO(Bug 1789718): Remove after the deprecated XPIProvider-based
- // implementation is also removed.
- if (type === "sitepermission-deprecated") {
- const xpi = AddonTestUtils.createTempWebExtensionFile(extensionOpts);
- const addon = await AddonManager.installTemporaryAddon(xpi);
- // The extension object that ExtensionTestUtils.loadExtension returns for
- // mochitest is pretty tight to the Extension class, and so for now this
- // returns a more minimal `extension` test object which only provides the
- // `unload` method.
- //
- // For the purpose of the abuse reports tests that are using this helper
- // this should be already enough.
- return {
- addon,
- unload: () => addon.uninstall(),
- };
- }
-
- const extension = ExtensionTestUtils.loadExtension(extensionOpts);
- await extension.startup();
- return extension;
-}
-
-function handleSubmitRequest({ request, response }) {
- response.setStatusLine(request.httpVersion, 200, "OK");
- response.setHeader("Content-Type", "application/json", false);
- response.write("{}");
-}
-
const AbuseReportTestUtils = {
_mockProvider: null,
_mockServer: null,
@@ -166,228 +43,14 @@ const AbuseReportTestUtils = {
// Mock addon details API endpoint.
amoAddonDetailsMap: new Map(),
- // Setup the test environment by setting the expected prefs and
- // initializing MockProvider and the mock AMO server.
+ // Setup the test environment by setting the expected prefs and initializing
+ // MockProvider.
async setup() {
- // Enable html about:addons and the abuse reporting and
- // set the api endpoints url to the mock service.
await SpecialPowers.pushPrefEnv({
- set: [
- ["extensions.abuseReport.enabled", true],
- ["extensions.abuseReport.url", "http://test.addons.org/api/report/"],
- [
- "extensions.abuseReport.amoDetailsURL",
- "http://test.addons.org/api/addons/addon/",
- ],
- ],
+ set: [["extensions.abuseReport.enabled", true]],
});
this._setupMockProvider();
- this._setupMockServer();
- },
-
- // Returns the currently open abuse report dialog window (if any).
- getReportDialog() {
- return Services.ww.getWindowByName("addons-abuse-report-dialog");
- },
-
- // Returns the parameters related to the report dialog (if any).
- getReportDialogParams() {
- const win = this.getReportDialog();
- return win && win.arguments[0] && win.arguments[0].wrappedJSObject;
- },
-
- // Returns a reference to the addon-abuse-report element from the currently
- // open abuse report.
- getReportPanel() {
- const win = this.getReportDialog();
- ok(win, "Got an abuse report dialog open");
- return win && win.document.querySelector("addon-abuse-report");
- },
-
- // Returns the list of abuse report reasons.
- getReasons(abuseReportEl) {
- return Object.keys(abuseReportEl.ownerGlobal.ABUSE_REPORT_REASONS);
- },
-
- // Returns the info related to a given abuse report reason.
- getReasonInfo(abuseReportEl, reason) {
- return abuseReportEl.ownerGlobal.ABUSE_REPORT_REASONS[reason];
- },
-
- async promiseReportOpened({ addonId, reportEntryPoint }) {
- let abuseReportEl;
-
- if (!this.getReportDialog()) {
- info("Wait for the report dialog window");
- const dialog = await waitForNewWindow();
- is(dialog, this.getReportDialog(), "Report dialog opened");
- }
-
- info("Wait for the abuse report panel render");
- abuseReportEl = await AbuseReportTestUtils.promiseReportDialogRendered();
-
- ok(abuseReportEl, "Got an abuse report panel");
- is(
- abuseReportEl.addon && abuseReportEl.addon.id,
- addonId,
- "Abuse Report panel rendered for the expected addonId"
- );
- is(
- abuseReportEl._report && abuseReportEl._report.reportEntryPoint,
- reportEntryPoint,
- "Abuse Report panel rendered for the expected reportEntryPoint"
- );
-
- return abuseReportEl;
- },
-
- // Return a promise resolved when the currently open report panel
- // is closed.
- // Also asserts that a specific report panel element has been closed,
- // if one has been provided through the optional panel parameter.
- async promiseReportClosed(panel) {
- const win = panel ? panel.ownerGlobal : this.getReportDialog();
- if (!win || win.closed) {
- throw Error("Expected report dialog not found or already closed");
- }
-
- await waitClosedWindow(win);
- // Assert that the panel has been closed (if the caller has passed it).
- if (panel) {
- ok(!panel.ownerGlobal, "abuse report dialog closed");
- }
- },
-
- // Returns a promise resolved when the report panel has been rendered
- // (rejects is there is no dialog currently open).
- async promiseReportDialogRendered() {
- const params = this.getReportDialogParams();
- if (!params) {
- throw new Error("abuse report dialog not found");
- }
- return params.promiseReportPanel;
- },
-
- // Given a `requestHandler` function, an HTTP server handler function
- // to use to handle a report submit request received by the mock AMO server),
- // returns a promise resolved when the mock AMO server has received and
- // handled the report submit request.
- async promiseReportSubmitHandled(requestHandler) {
- if (typeof requestHandler !== "function") {
- throw new Error("requestHandler should be a function");
- }
- return new Promise((resolve, reject) => {
- this._abuseRequestHandlers.unshift({ resolve, reject, requestHandler });
- });
- },
-
- // Return a promise resolved to the abuse report panel element,
- // once its rendering is completed.
- // If abuseReportEl is undefined, it looks for the currently opened
- // report panel.
- async promiseReportRendered(abuseReportEl) {
- let el = abuseReportEl;
-
- if (!el) {
- const win = this.getReportDialog();
- if (!win) {
- await waitForNewWindow();
- }
-
- el = await this.promiseReportDialogRendered();
- ok(el, "Got an abuse report panel");
- }
-
- return el._radioCheckedReason
- ? el
- : BrowserTestUtils.waitForEvent(
- el,
- "abuse-report:updated",
- "Wait the abuse report panel to be rendered"
- ).then(() => el);
- },
-
- // A promise resolved when the given abuse report panel element
- // has been rendered. If a panel name ("reasons" or "submit") is
- // passed as a second parameter, it also asserts that the panel is
- // updated to the expected view mode.
- async promiseReportUpdated(abuseReportEl, panel) {
- const evt = await BrowserTestUtils.waitForEvent(
- abuseReportEl,
- "abuse-report:updated",
- "Wait abuse report panel update"
- );
-
- if (panel) {
- is(evt.detail.panel, panel, `Got a "${panel}" update event`);
-
- const el = abuseReportEl;
- switch (evt.detail.panel) {
- case "reasons":
- ok(!el._reasonsPanel.hidden, "Reasons panel should be visible");
- ok(el._submitPanel.hidden, "Submit panel should be hidden");
- break;
- case "submit":
- ok(el._reasonsPanel.hidden, "Reasons panel should be hidden");
- ok(!el._submitPanel.hidden, "Submit panel should be visible");
- break;
- }
- }
- },
-
- // Returns a promise resolved once the expected number of abuse report
- // message bars have been created.
- promiseMessageBars(expectedMessageBarCount) {
- return new Promise(resolve => {
- const details = [];
- function listener(evt) {
- details.push(evt.detail);
- if (details.length >= expectedMessageBarCount) {
- cleanup();
- resolve(details);
- }
- }
- function cleanup() {
- if (gManagerWindow) {
- gManagerWindow.document.removeEventListener(
- "abuse-report:new-message-bar",
- listener
- );
- }
- }
- gManagerWindow.document.addEventListener(
- "abuse-report:new-message-bar",
- listener
- );
- });
- },
-
- async assertFluentStrings(containerEl) {
- // Make sure all localized elements have defined Fluent strings.
- let localizedEls = Array.from(
- containerEl.querySelectorAll("[data-l10n-id]")
- );
- if (containerEl.getAttribute("data-l10n-id")) {
- localizedEls.push(containerEl);
- }
- ok(localizedEls.length, "Got localized elements");
- for (let el of localizedEls) {
- const l10nId = el.getAttribute("data-l10n-id");
- const l10nAttrs = el.getAttribute("data-l10n-attrs");
- if (!l10nAttrs) {
- await TestUtils.waitForCondition(
- () => el.textContent !== "",
- `Element with Fluent id '${l10nId}' should not be empty`
- );
- } else {
- await TestUtils.waitForCondition(
- () => el.message !== "",
- `Message attribute of the element with Fluent id '${l10nId}'
- should not be empty`
- );
- }
- }
},
// Assert that the report action visibility on the addon card
@@ -419,68 +82,6 @@ const AbuseReportTestUtils = {
return this.assertReportActionVisibility(gManagerWindow, extId, true);
},
- // Assert that the report panel is hidden (or closed if the report
- // panel is opened in its own dialog window).
- async assertReportPanelHidden() {
- const win = this.getReportDialog();
- ok(!win, "Abuse Report dialog should be initially hidden");
- },
-
- createMockAddons(mockProviderAddons) {
- this._mockProvider.createAddons(mockProviderAddons);
- },
-
- async clickPanelButton(buttonEl, { label = undefined } = {}) {
- info(`Clicking the '${buttonEl.textContent.trim() || label}' button`);
- // NOTE: ideally this should synthesize the mouse event,
- // we call the click method to prevent intermittent timeouts
- // due to the mouse event not received by the target element.
- buttonEl.click();
- },
-
- triggerNewReport(addonId, reportEntryPoint) {
- gManagerWindow.openAbuseReport({ addonId, reportEntryPoint });
- },
-
- triggerSubmit(reason, message) {
- const reportEl =
- this.getReportDialog().document.querySelector("addon-abuse-report");
- reportEl._form.elements.message.value = message;
- reportEl._form.elements.reason.value = reason;
- reportEl.submit();
- },
-
- async openReport(addonId, reportEntryPoint = REPORT_ENTRY_POINT) {
- // Close the current about:addons window if it has been leaved open from
- // a previous test case failure.
- if (gManagerWindow) {
- await closeAboutAddons();
- }
-
- await openAboutAddons();
-
- let promiseReportPanel = waitForNewWindow().then(() =>
- this.promiseReportDialogRendered()
- );
-
- this.triggerNewReport(addonId, reportEntryPoint);
-
- const panelEl = await promiseReportPanel;
- await this.promiseReportRendered(panelEl);
- is(panelEl.addonId, addonId, `Got Abuse Report panel for ${addonId}`);
-
- return panelEl;
- },
-
- async closeReportPanel(panelEl) {
- const onceReportClosed = AbuseReportTestUtils.promiseReportClosed(panelEl);
-
- info("Cancel report and wait the dialog to be closed");
- panelEl.dispatchEvent(new CustomEvent("abuse-report:cancel"));
-
- await onceReportClosed;
- },
-
// Internal helper methods.
_setupMockProvider() {
@@ -529,87 +130,4 @@ const AbuseReportTestUtils = {
},
]);
},
-
- _setupMockServer() {
- if (this._mockServer) {
- return;
- }
-
- // Init test report api server.
- const server = AddonTestUtils.createHttpServer({
- hosts: ["test.addons.org"],
- });
- this._mockServer = server;
-
- server.registerPathHandler("/api/report/", (request, response) => {
- const stream = request.bodyInputStream;
- const buffer = NetUtil.readInputStream(stream, stream.available());
- const data = new TextDecoder().decode(buffer);
- const promisedHandler = this._abuseRequestHandlers.pop();
- if (promisedHandler) {
- const { requestHandler, resolve, reject } = promisedHandler;
- try {
- requestHandler({ data, request, response });
- resolve();
- } catch (err) {
- ok(false, `Unexpected requestHandler error ${err} ${err.stack}\n`);
- reject(err);
- }
- } else {
- ok(false, `Unexpected request: ${request.path} ${data}`);
- }
- });
-
- server.registerPrefixHandler("/api/addons/addon/", (request, response) => {
- const addonId = request.path.split("/").pop();
- if (!this.amoAddonDetailsMap.has(addonId)) {
- response.setStatusLine(request.httpVersion, 404, "Not Found");
- response.write(JSON.stringify({ detail: "Not found." }));
- } else {
- response.setStatusLine(request.httpVersion, 200, "Success");
- response.write(JSON.stringify(this.amoAddonDetailsMap.get(addonId)));
- }
- });
- server.registerPathHandler(
- "/assets/fake-icon-url.png",
- (request, response) => {
- response.setStatusLine(request.httpVersion, 200, "Success");
- response.write("");
- response.finish();
- }
- );
- },
};
-
-function createPromptConfirmEx({
- remove = false,
- report = false,
- expectCheckboxHidden = false,
-} = {}) {
- return (...args) => {
- const checkboxState = args.pop();
- const checkboxMessage = args.pop();
- is(
- checkboxState && checkboxState.value,
- false,
- "checkboxState should be initially false"
- );
- if (expectCheckboxHidden) {
- ok(
- !checkboxMessage,
- "Should not have a checkboxMessage in promptService.confirmEx call"
- );
- } else {
- ok(
- checkboxMessage,
- "Got a checkboxMessage in promptService.confirmEx call"
- );
- }
-
- // Report checkbox selected.
- checkboxState.value = report;
-
- // Remove accepted.
- return remove ? 0 : 1;
- };
-}
diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js b/toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js
index c94ef29e31..4fe0821c70 100644
--- a/toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js
@@ -2,88 +2,21 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
-const { AbuseReporter, AbuseReportError } = ChromeUtils.importESModule(
+const { AbuseReporter } = ChromeUtils.importESModule(
"resource://gre/modules/AbuseReporter.sys.mjs"
);
const { ClientID } = ChromeUtils.importESModule(
"resource://gre/modules/ClientID.sys.mjs"
);
-const { TelemetryController } = ChromeUtils.importESModule(
- "resource://gre/modules/TelemetryController.sys.mjs"
-);
-const { TelemetryTestUtils } = ChromeUtils.importESModule(
- "resource://testing-common/TelemetryTestUtils.sys.mjs"
-);
const APPNAME = "XPCShell";
const APPVERSION = "1";
const ADDON_ID = "test-addon@tests.mozilla.org";
-const ADDON_ID2 = "test-addon2@tests.mozilla.org";
const FAKE_INSTALL_INFO = {
source: "fake-Install:Source",
method: "fake:install method",
};
-const PREF_REQUIRED_LOCALE = "intl.locale.requested";
-const REPORT_OPTIONS = { reportEntryPoint: "menu" };
-const TELEMETRY_EVENTS_FILTERS = {
- category: "addonsManager",
- method: "report",
-};
-
-const FAKE_AMO_DETAILS = {
- name: {
- "en-US": "fake name",
- "it-IT": "fake it-IT name",
- },
- current_version: { version: "1.0" },
- type: "extension",
- is_recommended: true,
-};
-
-createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "49");
-
-const server = createHttpServer({ hosts: ["test.addons.org"] });
-
-// Mock abuse report API endpoint.
-let apiRequestHandler;
-server.registerPathHandler("/api/report/", (request, response) => {
- const stream = request.bodyInputStream;
- const buffer = NetUtil.readInputStream(stream, stream.available());
- const data = new TextDecoder().decode(buffer);
- apiRequestHandler({ data, request, response });
-});
-
-// Mock addon details API endpoint.
-const amoAddonDetailsMap = new Map();
-server.registerPrefixHandler("/api/addons/addon/", (request, response) => {
- const addonId = request.path.split("/").pop();
- if (!amoAddonDetailsMap.has(addonId)) {
- response.setStatusLine(request.httpVersion, 404, "Not Found");
- response.write(JSON.stringify({ detail: "Not found." }));
- } else {
- response.setStatusLine(request.httpVersion, 200, "Success");
- response.write(JSON.stringify(amoAddonDetailsMap.get(addonId)));
- }
-});
-
-function getProperties(obj, propNames) {
- return propNames.reduce((acc, el) => {
- acc[el] = obj[el];
- return acc;
- }, {});
-}
-
-function handleSubmitRequest({ request, response }) {
- response.setStatusLine(request.httpVersion, 200, "OK");
- response.setHeader("Content-Type", "application/json", false);
- response.write("{}");
-}
-
-function clearAbuseReportState() {
- // Clear the timestamp of the last submission.
- AbuseReporter._lastReportTimestamp = null;
-}
async function installTestExtension(overrideOptions = {}) {
const extOptions = {
@@ -104,34 +37,6 @@ async function installTestExtension(overrideOptions = {}) {
return { extension, addon };
}
-async function assertRejectsAbuseReportError(promise, errorType, errorInfo) {
- let error;
-
- await Assert.rejects(
- promise,
- err => {
- // Log the actual error to make investigating test failures easier.
- Cu.reportError(err);
- error = err;
- return err instanceof AbuseReportError;
- },
- `Got an AbuseReportError`
- );
-
- equal(error.errorType, errorType, "Got the expected errorType");
- equal(error.errorInfo, errorInfo, "Got the expected errorInfo");
- ok(
- error.message.includes(errorType),
- "errorType should be included in the error message"
- );
- if (errorInfo) {
- ok(
- error.message.includes(errorInfo),
- "errorInfo should be included in the error message"
- );
- }
-}
-
async function assertBaseReportData({ reportData, addon }) {
// Report properties related to addon metadata.
equal(reportData.addon, ADDON_ID, "Got expected 'addon'");
@@ -191,42 +96,10 @@ async function assertBaseReportData({ reportData, addon }) {
);
}
-add_task(async function test_setup() {
- Services.prefs.setCharPref(
- "extensions.abuseReport.url",
- "http://test.addons.org/api/report/"
- );
-
- Services.prefs.setCharPref(
- "extensions.abuseReport.amoDetailsURL",
- "http://test.addons.org/api/addons/addon"
- );
+createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "49");
+add_setup(async () => {
await promiseStartupManager();
- // Telemetry test setup needed to ensure that the builtin events are defined
- // and they can be collected and verified.
- await TelemetryController.testSetup();
-
- // This is actually only needed on Android, because it does not properly support unified telemetry
- // and so, if not enabled explicitly here, it would make these tests to fail when running on a
- // non-Nightly build.
- const oldCanRecordBase = Services.telemetry.canRecordBase;
- Services.telemetry.canRecordBase = true;
- registerCleanupFunction(() => {
- Services.telemetry.canRecordBase = oldCanRecordBase;
- });
-
- // Register a fake it-IT locale (used to test localized AMO details in some
- // of the test case defined in this test file).
- L10nRegistry.getInstance().registerSources([
- L10nFileSource.createMock(
- "mock",
- "app",
- ["it-IT", "fr-FR"],
- "resource://fake/locales/{locale}",
- []
- ),
- ]);
});
add_task(async function test_addon_report_data() {
@@ -260,37 +133,6 @@ add_task(async function test_addon_report_data() {
await extension3.unload();
});
-add_task(async function test_report_on_not_installed_addon() {
- Services.telemetry.clearEvents();
-
- // Make sure that the AMO addons details API endpoint is going to
- // return a 404 status for the not installed addon.
- amoAddonDetailsMap.delete(ADDON_ID);
-
- await assertRejectsAbuseReportError(
- AbuseReporter.createAbuseReport(ADDON_ID, REPORT_OPTIONS),
- "ERROR_ADDON_NOTFOUND"
- );
-
- TelemetryTestUtils.assertEvents(
- [
- {
- object: REPORT_OPTIONS.reportEntryPoint,
- value: ADDON_ID,
- extra: { error_type: "ERROR_AMODETAILS_NOTFOUND" },
- },
- {
- object: REPORT_OPTIONS.reportEntryPoint,
- value: ADDON_ID,
- extra: { error_type: "ERROR_ADDON_NOTFOUND" },
- },
- ],
- TELEMETRY_EVENTS_FILTERS
- );
-
- Services.telemetry.clearEvents();
-});
-
// This tests verifies how the addon installTelemetryInfo values are being
// normalized into the addon_install_source and addon_install_method
// expected by the API endpoint.
@@ -379,526 +221,3 @@ add_task(async function test_normalized_addon_install_source_and_method() {
await assertAddonInstallMethod(test, expect);
}
});
-
-add_task(async function test_report_create_and_submit() {
- Services.telemetry.clearEvents();
-
- // Override the test api server request handler, to be able to
- // intercept the submittions to the test api server.
- let reportSubmitted;
- apiRequestHandler = ({ data, request, response }) => {
- reportSubmitted = JSON.parse(data);
- handleSubmitRequest({ request, response });
- };
-
- const { addon, extension } = await installTestExtension();
-
- const reportEntryPoint = "menu";
- const report = await AbuseReporter.createAbuseReport(ADDON_ID, {
- reportEntryPoint,
- });
-
- equal(report.addon, addon, "Got the expected addon property");
- equal(
- report.reportEntryPoint,
- reportEntryPoint,
- "Got the expected reportEntryPoint"
- );
-
- const baseReportData = await AbuseReporter.getReportData(addon);
- const reportProperties = {
- message: "test message",
- reason: "test-reason",
- };
-
- info("Submitting report");
- report.setMessage(reportProperties.message);
- report.setReason(reportProperties.reason);
- await report.submit();
-
- const expectedEntries = Object.entries({
- report_entry_point: reportEntryPoint,
- ...baseReportData,
- ...reportProperties,
- });
-
- for (const [expectedKey, expectedValue] of expectedEntries) {
- equal(
- reportSubmitted[expectedKey],
- expectedValue,
- `Got the expected submitted value for "${expectedKey}"`
- );
- }
-
- TelemetryTestUtils.assertEvents(
- [
- {
- object: reportEntryPoint,
- value: ADDON_ID,
- extra: { addon_type: "extension" },
- },
- ],
- TELEMETRY_EVENTS_FILTERS
- );
-
- await extension.unload();
-});
-
-add_task(async function test_error_recent_submit() {
- Services.telemetry.clearEvents();
- clearAbuseReportState();
-
- let reportSubmitted;
- apiRequestHandler = ({ data, request, response }) => {
- reportSubmitted = JSON.parse(data);
- handleSubmitRequest({ request, response });
- };
-
- const { extension } = await installTestExtension();
- const report = await AbuseReporter.createAbuseReport(ADDON_ID, {
- reportEntryPoint: "uninstall",
- });
-
- const { extension: extension2 } = await installTestExtension({
- manifest: {
- browser_specific_settings: { gecko: { id: ADDON_ID2 } },
- name: "Test Extension2",
- },
- });
- const report2 = await AbuseReporter.createAbuseReport(
- ADDON_ID2,
- REPORT_OPTIONS
- );
-
- // Submit the two reports in fast sequence.
- report.setReason("reason1");
- report2.setReason("reason2");
- await report.submit();
- await assertRejectsAbuseReportError(report2.submit(), "ERROR_RECENT_SUBMIT");
- equal(
- reportSubmitted.reason,
- "reason1",
- "Server only received the data from the first submission"
- );
-
- TelemetryTestUtils.assertEvents(
- [
- {
- object: "uninstall",
- value: ADDON_ID,
- extra: { addon_type: "extension" },
- },
- {
- object: REPORT_OPTIONS.reportEntryPoint,
- value: ADDON_ID2,
- extra: {
- addon_type: "extension",
- error_type: "ERROR_RECENT_SUBMIT",
- },
- },
- ],
- TELEMETRY_EVENTS_FILTERS
- );
-
- await extension.unload();
- await extension2.unload();
-});
-
-add_task(async function test_submission_server_error() {
- const { extension } = await installTestExtension();
-
- async function testErrorCode({
- responseStatus,
- responseText = "",
- expectedErrorType,
- expectedErrorInfo,
- expectRequest = true,
- }) {
- info(
- `Test expected AbuseReportError on response status "${responseStatus}"`
- );
- Services.telemetry.clearEvents();
- clearAbuseReportState();
-
- let requestReceived = false;
- apiRequestHandler = ({ request, response }) => {
- requestReceived = true;
- response.setStatusLine(request.httpVersion, responseStatus, "Error");
- response.write(responseText);
- };
-
- const report = await AbuseReporter.createAbuseReport(
- ADDON_ID,
- REPORT_OPTIONS
- );
- report.setReason("a-reason");
- const promiseSubmit = report.submit();
- if (typeof expectedErrorType === "string") {
- // Assert a specific AbuseReportError errorType.
- await assertRejectsAbuseReportError(
- promiseSubmit,
- expectedErrorType,
- expectedErrorInfo
- );
- } else {
- // Assert on a given Error class.
- await Assert.rejects(promiseSubmit, expectedErrorType);
- }
- equal(
- requestReceived,
- expectRequest,
- `${expectRequest ? "" : "Not "}received a request as expected`
- );
-
- TelemetryTestUtils.assertEvents(
- [
- {
- object: REPORT_OPTIONS.reportEntryPoint,
- value: ADDON_ID,
- extra: {
- addon_type: "extension",
- error_type:
- typeof expectedErrorType === "string"
- ? expectedErrorType
- : "ERROR_UNKNOWN",
- },
- },
- ],
- TELEMETRY_EVENTS_FILTERS
- );
- }
-
- await testErrorCode({
- responseStatus: 500,
- responseText: "A server error",
- expectedErrorType: "ERROR_SERVER",
- expectedErrorInfo: JSON.stringify({
- status: 500,
- responseText: "A server error",
- }),
- });
- await testErrorCode({
- responseStatus: 404,
- responseText: "Not found error",
- expectedErrorType: "ERROR_CLIENT",
- expectedErrorInfo: JSON.stringify({
- status: 404,
- responseText: "Not found error",
- }),
- });
- // Test response with unexpected status code.
- await testErrorCode({
- responseStatus: 604,
- responseText: "An unexpected status code",
- expectedErrorType: "ERROR_UNKNOWN",
- expectedErrorInfo: JSON.stringify({
- status: 604,
- responseText: "An unexpected status code",
- }),
- });
- // Test response status 200 with invalid json data.
- await testErrorCode({
- responseStatus: 200,
- expectedErrorType: /SyntaxError: JSON.parse/,
- });
-
- // Test on invalid url.
- Services.prefs.setCharPref(
- "extensions.abuseReport.url",
- "invalid-protocol://abuse-report"
- );
- await testErrorCode({
- expectedErrorType: "ERROR_NETWORK",
- expectRequest: false,
- });
-
- await extension.unload();
-});
-
-add_task(async function set_test_abusereport_url() {
- Services.prefs.setCharPref(
- "extensions.abuseReport.url",
- "http://test.addons.org/api/report/"
- );
-});
-
-add_task(async function test_submission_aborting() {
- Services.telemetry.clearEvents();
- clearAbuseReportState();
-
- const { extension } = await installTestExtension();
-
- // override the api request handler with one that is never going to reply.
- let receivedRequestsCount = 0;
- let resolvePendingResponses;
- const waitToReply = new Promise(
- resolve => (resolvePendingResponses = resolve)
- );
-
- const onRequestReceived = new Promise(resolve => {
- apiRequestHandler = ({ request, response }) => {
- response.processAsync();
- response.setStatusLine(request.httpVersion, 200, "OK");
- receivedRequestsCount++;
- resolve();
-
- // Keep the request pending until resolvePendingResponses have been
- // called.
- waitToReply.then(() => {
- response.finish();
- });
- };
- });
-
- const report = await AbuseReporter.createAbuseReport(
- ADDON_ID,
- REPORT_OPTIONS
- );
- report.setReason("a-reason");
- const promiseResult = report.submit();
-
- await onRequestReceived;
-
- Assert.greater(
- receivedRequestsCount,
- 0,
- "Got the expected number of requests"
- );
- Assert.strictEqual(
- await Promise.race([promiseResult, Promise.resolve("pending")]),
- "pending",
- "Submission fetch request should still be pending"
- );
-
- report.abort();
-
- await assertRejectsAbuseReportError(promiseResult, "ERROR_ABORTED_SUBMIT");
-
- TelemetryTestUtils.assertEvents(
- [
- {
- object: REPORT_OPTIONS.reportEntryPoint,
- value: ADDON_ID,
- extra: { addon_type: "extension", error_type: "ERROR_ABORTED_SUBMIT" },
- },
- ],
- TELEMETRY_EVENTS_FILTERS
- );
-
- await extension.unload();
-
- // Unblock pending requests on the server request handler side, so that the
- // test file can shutdown (otherwise the test run will be stuck after this
- // task completed).
- resolvePendingResponses();
-});
-
-add_task(async function test_truncated_string_properties() {
- const generateString = len => new Array(len).fill("a").join("");
-
- const LONG_STRINGS_ADDON_ID = "addon-with-long-strings-props@mochi.test";
- const { extension } = await installTestExtension({
- manifest: {
- name: generateString(400),
- description: generateString(400),
- browser_specific_settings: { gecko: { id: LONG_STRINGS_ADDON_ID } },
- },
- });
-
- // Override the test api server request handler, to be able to
- // intercept the properties actually submitted.
- let reportSubmitted;
- apiRequestHandler = ({ data, request, response }) => {
- reportSubmitted = JSON.parse(data);
- handleSubmitRequest({ request, response });
- };
-
- const report = await AbuseReporter.createAbuseReport(
- LONG_STRINGS_ADDON_ID,
- REPORT_OPTIONS
- );
-
- report.setMessage("fake-message");
- report.setReason("fake-reason");
- await report.submit();
-
- const expected = {
- addon_name: generateString(255),
- addon_summary: generateString(255),
- };
-
- Assert.deepEqual(
- {
- addon_name: reportSubmitted.addon_name,
- addon_summary: reportSubmitted.addon_summary,
- },
- expected,
- "Got the long strings truncated as expected"
- );
-
- await extension.unload();
-});
-
-add_task(async function test_report_recommended() {
- const NON_RECOMMENDED_ADDON_ID = "non-recommended-addon@mochi.test";
- const RECOMMENDED_ADDON_ID = "recommended-addon@mochi.test";
-
- const now = Date.now();
- const not_before = new Date(now - 3600000).toISOString();
- const not_after = new Date(now + 3600000).toISOString();
-
- const { extension: nonRecommended } = await installTestExtension({
- manifest: {
- name: "Fake non recommended addon",
- browser_specific_settings: { gecko: { id: NON_RECOMMENDED_ADDON_ID } },
- },
- });
-
- const { extension: recommended } = await installTestExtension({
- manifest: {
- name: "Fake recommended addon",
- browser_specific_settings: { gecko: { id: RECOMMENDED_ADDON_ID } },
- },
- files: {
- "mozilla-recommendation.json": {
- addon_id: RECOMMENDED_ADDON_ID,
- states: ["recommended"],
- validity: { not_before, not_after },
- },
- },
- });
-
- // Override the test api server request handler, to be able to
- // intercept the properties actually submitted.
- let reportSubmitted;
- apiRequestHandler = ({ data, request, response }) => {
- reportSubmitted = JSON.parse(data);
- handleSubmitRequest({ request, response });
- };
-
- async function checkReportedSignature(addonId, expectedAddonSignature) {
- clearAbuseReportState();
- const report = await AbuseReporter.createAbuseReport(
- addonId,
- REPORT_OPTIONS
- );
- report.setMessage("fake-message");
- report.setReason("fake-reason");
- await report.submit();
- equal(
- reportSubmitted.addon_signature,
- expectedAddonSignature,
- `Got the expected addon_signature for ${addonId}`
- );
- }
-
- await checkReportedSignature(NON_RECOMMENDED_ADDON_ID, "signed");
- await checkReportedSignature(RECOMMENDED_ADDON_ID, "curated");
-
- await nonRecommended.unload();
- await recommended.unload();
-});
-
-add_task(async function test_query_amo_details() {
- async function assertReportOnAMODetails({ addonId, expectedReport } = {}) {
- // Clear last report timestamp and any telemetry event recorded so far.
- clearAbuseReportState();
- Services.telemetry.clearEvents();
-
- const report = await AbuseReporter.createAbuseReport(addonId, {
- reportEntryPoint: "menu",
- });
-
- let reportSubmitted;
- apiRequestHandler = ({ data, request, response }) => {
- reportSubmitted = JSON.parse(data);
- handleSubmitRequest({ request, response });
- };
-
- report.setMessage("fake message");
- report.setReason("reason1");
- await report.submit();
-
- Assert.deepEqual(
- expectedReport,
- getProperties(reportSubmitted, Object.keys(expectedReport)),
- "Got the expected report properties"
- );
-
- // Telemetry recorded for the successfully submitted report.
- TelemetryTestUtils.assertEvents(
- [
- {
- object: "menu",
- value: addonId,
- extra: { addon_type: FAKE_AMO_DETAILS.type },
- },
- ],
- TELEMETRY_EVENTS_FILTERS
- );
-
- clearAbuseReportState();
- }
-
- // Add the expected AMO addons details.
- const addonId = "not-installed-addon@mochi.test";
- amoAddonDetailsMap.set(addonId, FAKE_AMO_DETAILS);
-
- // Test on the default en-US locale.
- Services.prefs.setCharPref(PREF_REQUIRED_LOCALE, "en-US");
- let locale = Services.locale.appLocaleAsBCP47;
- equal(locale, "en-US", "Got the expected app locale set");
-
- let expectedReport = {
- addon: addonId,
- addon_name: FAKE_AMO_DETAILS.name[locale],
- addon_version: FAKE_AMO_DETAILS.current_version.version,
- addon_install_source: "not_installed",
- addon_install_method: null,
- addon_signature: "curated",
- };
-
- await assertReportOnAMODetails({ addonId, expectedReport });
-
- // Test with a non-default locale also available in the AMO details.
- Services.prefs.setCharPref(PREF_REQUIRED_LOCALE, "it-IT");
- locale = Services.locale.appLocaleAsBCP47;
- equal(locale, "it-IT", "Got the expected app locale set");
-
- expectedReport = {
- ...expectedReport,
- addon_name: FAKE_AMO_DETAILS.name[locale],
- };
- await assertReportOnAMODetails({ addonId, expectedReport });
-
- // Test with a non-default locale not available in the AMO details.
- Services.prefs.setCharPref(PREF_REQUIRED_LOCALE, "fr-FR");
- locale = Services.locale.appLocaleAsBCP47;
- equal(locale, "fr-FR", "Got the expected app locale set");
-
- expectedReport = {
- ...expectedReport,
- // Fallbacks on en-US for non available locales.
- addon_name: FAKE_AMO_DETAILS.name["en-US"],
- };
- await assertReportOnAMODetails({ addonId, expectedReport });
-
- Services.prefs.clearUserPref(PREF_REQUIRED_LOCALE);
-
- amoAddonDetailsMap.clear();
-});
-
-add_task(async function test_statictheme_normalized_into_type_theme() {
- const themeId = "not-installed-statictheme@mochi.test";
- amoAddonDetailsMap.set(themeId, {
- ...FAKE_AMO_DETAILS,
- type: "statictheme",
- });
-
- const report = await AbuseReporter.createAbuseReport(themeId, REPORT_OPTIONS);
-
- equal(report.addon.id, themeId, "Got a report for the expected theme id");
- equal(report.addon.type, "theme", "Got the expected addon type");
-
- amoAddonDetailsMap.clear();
-});
diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_dictionary_webextension.js b/toolkit/mozapps/extensions/test/xpcshell/test_dictionary_webextension.js
index 1f52c8a8bc..bcb777e135 100644
--- a/toolkit/mozapps/extensions/test/xpcshell/test_dictionary_webextension.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_dictionary_webextension.js
@@ -10,7 +10,7 @@ XPCOMUtils.defineLazyServiceGetter(
"mozISpellCheckingEngine"
);
-add_task(async function setup() {
+add_setup(async function setup() {
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "61", "61");
// Initialize the URLPreloader so that we can load the built-in
@@ -18,6 +18,12 @@ add_task(async function setup() {
AddonTestUtils.initializeURLPreloader();
await promiseStartupManager();
+ // Sanity check, builtin dictionaries should be registered.
+ Assert.deepEqual(
+ spellCheck.getDictionaryList(),
+ ["en-US"],
+ "Expect en-US builtin dictionary to be registered"
+ );
// Starts collecting the Addon Manager Telemetry events.
AddonTestUtils.hookAMTelemetryEvents();
@@ -218,6 +224,13 @@ add_task(
const WORD = "Flehgragh";
add_task(async function test_registration() {
+ // Sanity check, builtin dictionaries should be registered.
+ Assert.deepEqual(
+ spellCheck.getDictionaryList(),
+ ["en-US"],
+ "Expect en-US builtin dictionary to be registered"
+ );
+
spellCheck.dictionaries = ["en-US"];
ok(!spellCheck.check(WORD), "Word should not pass check before add-on loads");
diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js b/toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js
index 913c802609..3551b2c8dd 100644
--- a/toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js
@@ -1,5 +1,14 @@
+AddonTestUtils.overrideCertDB();
+AddonTestUtils.usePrivilegedSignatures = id => id.startsWith("privileged-");
+
+// Some tests in this test file can't run on android build because
+// theme addon type isn't supported.
+const skipOnAndroid = () => ({
+ skip_if: () => AppConstants.platform === "android",
+});
+
let profileDir;
-add_task(async function setup() {
+add_setup(async function setup() {
profileDir = gProfD.clone();
profileDir.append("extensions");
@@ -19,7 +28,7 @@ const IMPLICIT_ID_ID = "{46607a7b-1b2a-40ce-9afe-91cda52c46a6}";
// webext-implicit-id.xpi has a minimal manifest with no
// applications or browser_specific_settings, so its id comes
// from its signature, which should be the ID constant defined below.
-add_task(async function test_implicit_id() {
+add_task(skipOnAndroid(), async function test_implicit_id() {
let addon = await promiseAddonByID(IMPLICIT_ID_ID);
equal(addon, null, "Add-on is not installed");
@@ -34,7 +43,7 @@ add_task(async function test_implicit_id() {
// We should also be able to install webext-implicit-id.xpi temporarily
// and it should look just like the regular install (ie, the ID should
// come from the signature)
-add_task(async function test_implicit_id_temp() {
+add_task(skipOnAndroid(), async function test_implicit_id_temp() {
let addon = await promiseAddonByID(IMPLICIT_ID_ID);
equal(addon, null, "Add-on is not installed");
@@ -602,6 +611,187 @@ add_task(async function test_permissions_prompt() {
await IOUtils.remove(xpi.path);
});
+// Check normalized optional origins.
+add_task(async function test_normalized_optional_origins() {
+ const assertAddonWrapperPermissionsProperties = async (
+ manifest,
+ expected
+ ) => {
+ let xpi = ExtensionTestCommon.generateXPI({ manifest });
+
+ let install = await AddonManager.getInstallForFile(xpi);
+
+ let perminfo;
+ let installPromptCompletedDeferred = Promise.withResolvers();
+ let installPromptShownDeferred = Promise.withResolvers();
+ install.promptHandler = info => {
+ perminfo = info;
+ installPromptShownDeferred.resolve();
+ return installPromptCompletedDeferred.promise;
+ };
+
+ const promiseInstalled = install.install();
+ info("Wait for the install prompt");
+ await installPromptShownDeferred.promise;
+
+ equal(
+ await promiseAddonByID(perminfo.addon.id),
+ null,
+ "Extension should not be installed yet"
+ );
+ notEqual(perminfo, undefined, "Permission handler was invoked");
+ notEqual(perminfo.addon, null, "Permission info includes the new addon");
+ equal(
+ perminfo.addon.isPrivileged,
+ expected.isPrivileged,
+ `Expect the addon to be ${expected.isPrivileged ? "" : "non-"}privileged`
+ );
+ let addon = perminfo.addon;
+ deepEqual(
+ addon.userPermissions,
+ expected.userPermissions,
+ "userPermissions are correct"
+ );
+ deepEqual(
+ addon.optionalPermissions,
+ expected.optionalPermissions,
+ "optionalPermissions are correct"
+ );
+ info("Assert normalized optional origins on non-installed extension");
+ deepEqual(
+ addon.optionalOriginsNormalized,
+ expected.optionalOriginsNormalized,
+ "optionalOriginsNormalized are correct"
+ );
+
+ installPromptCompletedDeferred.resolve();
+ await promiseInstalled;
+ addon = await promiseAddonByID(perminfo.addon.id);
+ notEqual(addon, null, "Extension was installed successfully");
+
+ info("Assert normalized optional origins again on installed extension");
+ deepEqual(
+ addon.optionalOriginsNormalized,
+ expected.optionalOriginsNormalized,
+ "Normalized origin permissions are correct"
+ );
+
+ await addon.uninstall();
+ await IOUtils.remove(xpi.path);
+ };
+
+ info(
+ "Test normalized optional origins on non-privileged ManifestV2 extension"
+ );
+ const manifestV2 = {
+ name: "permissions test mv2",
+ manifest_version: 2,
+ // Include a permission that would trigger an install time prompt.
+ permissions: ["tabs"],
+ // Include optional origins to be normalized.
+ // NOTE: we expect the normalized origins to be deduplicated.
+ optional_permissions: [
+ "http://*.example.com/",
+ "http://*.example.com/somepath/",
+ "*://example.org/*",
+ "*://example.org/another-path/*",
+ "file://*/*",
+ ],
+ };
+
+ await assertAddonWrapperPermissionsProperties(manifestV2, {
+ isPrivileged: false,
+ userPermissions: { permissions: manifestV2.permissions, origins: [] },
+ optionalPermissions: {
+ permissions: [],
+ origins: manifestV2.optional_permissions,
+ },
+ optionalOriginsNormalized: [
+ "http://*.example.com/*",
+ "*://example.org/*",
+ "file://*/*",
+ ],
+ });
+
+ info(
+ "Test normalized optional origins on non-privileged ManifestV3 extension"
+ );
+ const manifestV3 = {
+ name: "permissions test mv3",
+ manifest_version: 3,
+ // Include a permission that would trigger an install time prompt.
+ permissions: ["tabs"],
+
+ // Content Scripts match patterns are also expected to be part
+ // of the optional host permissions (and to be deduplicated).
+ content_scripts: [
+ {
+ matches: ["*://*/*"],
+ js: ["script.js"],
+ },
+ {
+ matches: ["*://example.org/*"],
+ js: ["script2.js"],
+ },
+ ],
+
+ // Include optional origins to be normalized.
+ host_permissions: [
+ "http://*.example.com/",
+ "*://example.org/*",
+ "file://*/*",
+ ],
+ };
+
+ await assertAddonWrapperPermissionsProperties(manifestV3, {
+ isPrivileged: false,
+ userPermissions: { permissions: manifestV3.permissions, origins: [] },
+ optionalPermissions: {
+ permissions: [],
+ origins: [...manifestV3.host_permissions, "*://*/*"],
+ },
+ optionalOriginsNormalized: [
+ "http://*.example.com/*",
+ "*://example.org/*",
+ "file://*/*",
+ "*://*/*",
+ ],
+ });
+
+ info("Test normalized optional origins on privileged ManifestV2 extension");
+ const manifestV2Privileged = {
+ name: "permissions test privileged mv2",
+ manifest_version: 2,
+ browser_specific_settings: { gecko: { id: "privileged-mv2@ext" } },
+ // Include a permission that would trigger an install time prompt.
+ permissions: ["tabs", "mozillaAddons"],
+ optional_permissions: [
+ "http://*.example.com/",
+ "*://example.org/*",
+ "file://*/*",
+ "resource://gre/",
+ ],
+ };
+
+ await assertAddonWrapperPermissionsProperties(manifestV2Privileged, {
+ isPrivileged: true,
+ userPermissions: {
+ permissions: manifestV2Privileged.permissions,
+ origins: [],
+ },
+ optionalPermissions: {
+ permissions: [],
+ origins: manifestV2Privileged.optional_permissions,
+ },
+ optionalOriginsNormalized: [
+ "http://*.example.com/*",
+ "*://example.org/*",
+ "file://*/*",
+ "resource://gre/*",
+ ],
+ });
+});
+
// Check permissions prompt cancellation
add_task(async function test_permissions_prompt_cancel() {
const manifest = {
diff --git a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.toml b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.toml
index e8d3807ab9..a342fad700 100644
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.toml
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.toml
@@ -1,5 +1,4 @@
[DEFAULT]
-skip-if = ["os == 'android'"]
tags = "addons"
head = "head_addons.js"
firefox-appdir = "browser"
@@ -11,252 +10,374 @@ support-files = [
"../xpinstall/amosigned-sha1only.xpi",
]
+# TODO: Most tests are skipped on Android but we should re-enable them,
+# cf. Bug 1872867.
+
["test_AMBrowserExtensionsImport.js"]
+skip-if = ["os == 'android'"]
["test_AbuseReporter.js"]
+skip-if = ["os == 'android'"]
["test_AddonRepository.js"]
+skip-if = ["os == 'android'"]
["test_AddonRepository_appIsShuttingDown.js"]
+skip-if = ["os == 'android'"]
["test_AddonRepository_cache.js"]
+skip-if = ["os == 'android'"]
["test_AddonRepository_cache_locale.js"]
+skip-if = ["os == 'android'"]
["test_AddonRepository_langpacks.js"]
+skip-if = ["os == 'android'"]
["test_AddonRepository_paging.js"]
+skip-if = ["os == 'android'"]
["test_ProductAddonChecker.js"]
+skip-if = ["os == 'android'"]
["test_ProductAddonChecker_signatures.js"]
head = "head_addons.js head_cert_handling.js"
+skip-if = ["os == 'android'"]
["test_QuarantinedDomains_AMRemoteSettings.js"]
head = "head_addons.js head_amremotesettings.js ../../../../components/extensions/test/xpcshell/head_telemetry.js"
+skip-if = ["os == 'android'"]
["test_QuarantinedDomains_AddonWrapper.js"]
+skip-if = ["os == 'android'"]
["test_XPIStates.js"]
-skip-if = ["condprof"] # Bug 1769184 - by design for now
+skip-if = [
+ "condprof", # Bug 1769184 - by design for now
+ "os == 'android'",
+]
["test_XPIcancel.js"]
+skip-if = ["os == 'android'"]
["test_addonStartup.js"]
+skip-if = ["os == 'android'"]
["test_addon_manager_telemetry_events.js"]
+skip-if = ["os == 'android'"]
["test_amo_stats_telemetry.js"]
+skip-if = ["os == 'android'"]
["test_aom_startup.js"]
+skip-if = ["os == 'android'"]
["test_bad_json.js"]
+skip-if = ["os == 'android'"]
["test_badschema.js"]
+skip-if = ["os == 'android'"]
["test_builtin_location.js"]
+skip-if = ["os == 'android'"]
["test_cacheflush.js"]
+skip-if = ["os == 'android'"]
["test_childprocess.js"]
head = ""
+skip-if = ["os == 'android'"]
["test_colorways_builtin_theme_upgrades.js"]
-skip-if = ["appname == 'thunderbird'"] # Bug 1809438 - No colorways in Thunderbird
+skip-if = [
+ "appname == 'thunderbird'", # Bug 1809438 - No colorways in Thunderbird
+ "os == 'android'",
+]
["test_cookies.js"]
+skip-if = ["os == 'android'"]
["test_corrupt.js"]
+skip-if = ["os == 'android'"]
["test_crash_annotation_quoting.js"]
+skip-if = ["os == 'android'"]
["test_db_path.js"]
head = ""
+skip-if = ["os == 'android'"]
["test_delay_update_webextension.js"]
tags = "webextensions"
+skip-if = ["os == 'android'"]
["test_dependencies.js"]
+skip-if = ["os == 'android'"]
["test_dictionary_webextension.js"]
+skip-if = ["os == 'android'"]
["test_distribution.js"]
+skip-if = ["os == 'android'"]
["test_distribution_langpack.js"]
+skip-if = ["os == 'android'"]
["test_embedderDisabled.js"]
+skip-if = ["os == 'android'"]
["test_error.js"]
-skip-if = ["os == 'win'"] # Bug 1508482
+skip-if = [
+ "os == 'win'", # Bug 1508482
+ "os == 'android'",
+]
["test_ext_management.js"]
tags = "webextensions"
+skip-if = ["os == 'android'"]
["test_general.js"]
+skip-if = ["os == 'android'"]
["test_getInstallSourceFromHost.js"]
+skip-if = ["os == 'android'"]
["test_gmpProvider.js"]
-skip-if = ["appname != 'firefox'"]
+skip-if = [
+ "appname != 'firefox'",
+ "os == 'android'",
+]
["test_harness.js"]
+skip-if = ["os == 'android'"]
["test_hidden.js"]
+skip-if = ["os == 'android'"]
["test_install.js"]
+skip-if = ["os == 'android'"]
["test_installOrigins.js"]
+skip-if = ["os == 'android'"]
["test_install_cancel.js"]
+skip-if = ["os == 'android'"]
["test_install_file_change.js"]
+skip-if = ["os == 'android'"]
["test_install_icons.js"]
+skip-if = ["os == 'android'"]
["test_installtrigger_deprecation.js"]
head = "head_addons.js head_amremotesettings.js"
+skip-if = ["os == 'android'"]
["test_installtrigger_schemes.js"]
+skip-if = ["os == 'android'"]
["test_isDebuggable.js"]
+skip-if = ["os == 'android'"]
["test_isReady.js"]
+skip-if = ["os == 'android'"]
["test_loadManifest_isPrivileged.js"]
+skip-if = ["os == 'android'"]
["test_locale.js"]
+skip-if = ["os == 'android'"]
["test_moved_extension_metadata.js"]
skip-if = ["true"] # bug 1777900
["test_no_addons.js"]
+skip-if = ["os == 'android'"]
["test_nodisable_hidden.js"]
+skip-if = ["os == 'android'"]
["test_onPropertyChanged_appDisabled.js"]
head = "head_addons.js head_compat.js"
-skip-if = ["tsan"] # Times out, bug 1674773
+skip-if = [
+ "tsan", # Times out, bug 1674773
+ "os == 'android'",
+]
["test_permissions.js"]
+skip-if = ["os == 'android'"]
["test_permissions_prefs.js"]
+skip-if = ["os == 'android'"]
["test_pref_properties.js"]
+skip-if = ["os == 'android'"]
["test_provider_markSafe.js"]
+skip-if = ["os == 'android'"]
["test_provider_shutdown.js"]
+skip-if = ["os == 'android'"]
["test_provider_unsafe_access_shutdown.js"]
+skip-if = ["os == 'android'"]
["test_provider_unsafe_access_startup.js"]
+skip-if = ["os == 'android'"]
["test_proxies.js"]
-skip-if = ["require_signing"]
+skip-if = [
+ "require_signing",
+ "os == 'android'",
+]
["test_recommendations.js"]
-skip-if = ["require_signing"]
+skip-if = [
+ "require_signing",
+ "os == 'android'",
+]
["test_registerchrome.js"]
+skip-if = ["os == 'android'"]
["test_registry.js"]
run-if = ["os == 'win'"]
+skip-if = ["os == 'android'"]
["test_reinstall_disabled_addon.js"]
+skip-if = ["os == 'android'"]
["test_reload.js"]
-skip-if = ["os == 'win'"] # There's a problem removing a temp file without manually clearing the cache on Windows
+skip-if = [
+ "os == 'win'", # There's a problem removing a temp file without manually clearing the cache on Windows
+ "os == 'android'",
+]
tags = "webextensions"
["test_remote_pref_telemetry.js"]
+skip-if = ["os == 'android'"]
["test_safemode.js"]
+skip-if = ["os == 'android'"]
["test_schema_change.js"]
+skip-if = ["os == 'android'"]
["test_seen.js"]
+skip-if = ["os == 'android'"]
["test_shutdown.js"]
+skip-if = ["os == 'android'"]
["test_shutdown_barriers.js"]
+skip-if = ["os == 'android'"]
["test_shutdown_early.js"]
-skip-if = ["condprof"] # Bug 1769184 - by design for now
+skip-if = [
+ "condprof", # Bug 1769184 - by design for now
+ "os == 'android'",
+]
["test_sideload_scopes.js"]
head = "head_addons.js head_sideload.js"
skip-if = [
"os == 'linux'", # Bug 1613268
"condprof", # Bug 1769184 - by design for now
+ "os == 'android'",
]
["test_sideloads.js"]
+skip-if = ["os == 'android'"]
["test_sideloads_after_rebuild.js"]
-skip-if = ["condprof"] # Bug 1769184 - by design for now
+skip-if = [
+ "condprof", # Bug 1769184 - by design for now
+ "os == 'android'",
+]
head = "head_addons.js head_sideload.js"
["test_signed_inject.js"]
skip-if = ["true"] # Bug 1394122
["test_signed_install.js"]
+skip-if = ["os == 'android'"]
["test_signed_langpack.js"]
+skip-if = ["os == 'android'"]
["test_signed_long.js"]
+skip-if = ["os == 'android'"]
["test_signed_updatepref.js"]
skip-if = [
"require_signing",
"!allow_legacy_extensions",
+ "os == 'android'",
]
["test_signed_verify.js"]
["test_sitePermsAddonProvider.js"]
-skip-if = ["appname == 'thunderbird'"] # Disabled in extensions.manifest
+skip-if = [
+ "appname == 'thunderbird'", # Disabled in extensions.manifest
+ "os == 'android'",
+]
["test_startup.js"]
head = "head_addons.js head_sideload.js"
skip-if = [
"os == 'linux'", # Bug 1613268
"condprof", # Bug 1769184 - by design for now
+ "os == 'android'",
]
["test_startup_enable.js"]
+skip-if = ["os == 'android'"]
["test_startup_isPrivileged.js"]
+skip-if = ["os == 'android'"]
["test_startup_scan.js"]
head = "head_addons.js head_sideload.js"
+skip-if = ["os == 'android'"]
["test_strictcompatibility.js"]
head = "head_addons.js head_compat.js"
+skip-if = ["os == 'android'"]
["test_syncGUID.js"]
+skip-if = ["os == 'android'"]
["test_system_allowed.js"]
head = "head_addons.js head_system_addons.js"
+skip-if = ["os == 'android'"]
["test_system_delay_update.js"]
head = "head_addons.js head_system_addons.js"
+skip-if = ["os == 'android'"]
["test_system_profile_location.js"]
+skip-if = ["os == 'android'"]
["test_system_repository.js"]
head = "head_addons.js head_system_addons.js"
+skip-if = ["os == 'android'"]
["test_system_reset.js"]
head = "head_addons.js head_system_addons.js"
+skip-if = ["os == 'android'"]
["test_system_update_blank.js"]
head = "head_addons.js head_system_addons.js"
+skip-if = ["os == 'android'"]
["test_system_update_checkSizeHash.js"]
head = "head_addons.js head_system_addons.js"
+skip-if = ["os == 'android'"]
["test_system_update_custom.js"]
head = "head_addons.js head_system_addons.js"
+skip-if = ["os == 'android'"]
["test_system_update_empty.js"]
head = "head_addons.js head_system_addons.js"
@@ -264,104 +385,148 @@ skip-if = ["true"] # Failing intermittently due to a race condition in the test,
["test_system_update_enterprisepolicy.js"]
head = "head_addons.js head_system_addons.js"
+skip-if = ["os == 'android'"]
["test_system_update_fail.js"]
head = "head_addons.js head_system_addons.js"
+skip-if = ["os == 'android'"]
["test_system_update_installTelemetryInfo.js"]
head = "head_addons.js head_system_addons.js"
+skip-if = ["os == 'android'"]
["test_system_update_newset.js"]
head = "head_addons.js head_system_addons.js"
+skip-if = ["os == 'android'"]
["test_system_update_overlapping.js"]
head = "head_addons.js head_system_addons.js"
+skip-if = ["os == 'android'"]
["test_system_update_uninstall_check.js"]
head = "head_addons.js head_system_addons.js"
+skip-if = ["os == 'android'"]
["test_system_update_upgrades.js"]
head = "head_addons.js head_system_addons.js"
+skip-if = ["os == 'android'"]
["test_system_upgrades.js"]
-skip-if = ["condprof"] # Bug 1769184 - by design for now
+skip-if = [
+ "condprof", # Bug 1769184 - by design for now
+ "os == 'android'",
+]
head = "head_addons.js head_system_addons.js"
["test_systemaddomstartupprefs.js"]
-skip-if = ["condprof"] # Bug 1769184 - by design for now
+skip-if = [
+ "condprof", # Bug 1769184 - by design for now
+ "os == 'android'",
+]
head = "head_addons.js head_system_addons.js"
["test_temporary.js"]
-skip-if = ["os == 'win'"] # Bug 1469904
+skip-if = [
+ "os == 'win'", # Bug 1469904
+ "os == 'android'",
+]
tags = "webextensions"
["test_trash_directory.js"]
run-if = ["os == 'win'"]
+skip-if = ["os == 'android'"]
["test_types.js"]
["test_undouninstall.js"]
-skip-if = ["os == 'win'"] # Bug 1358846
+skip-if = [
+ "os == 'win'", # Bug 1358846
+ "os == 'android'",
+]
["test_update.js"]
+skip-if = ["os == 'android'"]
["test_updateCancel.js"]
+skip-if = ["os == 'android'"]
["test_update_addontype.js"]
+skip-if = ["os == 'android'"]
["test_update_compatmode.js"]
head = "head_addons.js head_compat.js"
+skip-if = ["os == 'android'"]
["test_update_ignorecompat.js"]
skip-if = ["true"] # Bug 676922 Bug 1437697
["test_update_isPrivileged.js"]
-skip-if = ["condprof"] # Bug 1769184 - by design for now
+skip-if = [
+ "condprof", # Bug 1769184 - by design for now
+ "os == 'android'",
+]
["test_update_noSystemAddonUpdate.js"]
head = "head_addons.js head_system_addons.js"
+skip-if = ["os == 'android'"]
["test_update_strictcompat.js"]
head = "head_addons.js head_compat.js"
+skip-if = ["os == 'android'"]
["test_update_theme.js"]
+skip-if = ["os == 'android'"]
["test_update_webextensions.js"]
tags = "webextensions"
+skip-if = ["os == 'android'"]
["test_updatecheck.js"]
+skip-if = ["os == 'android'"]
["test_updatecheck_errors.js"]
+skip-if = ["os == 'android'"]
["test_updatecheck_json.js"]
+skip-if = ["os == 'android'"]
["test_updateid.js"]
+skip-if = ["os == 'android'"]
["test_updateversion.js"]
+skip-if = ["os == 'android'"]
["test_upgrade.js"]
head = "head_addons.js head_compat.js"
run-sequentially = "Uses global XCurProcD dir."
+skip-if = ["os == 'android'"]
["test_upgrade_incompatible.js"]
+skip-if = ["os == 'android'"]
["test_webextension.js"]
tags = "webextensions"
+skip-if = ["os == 'android'"]
["test_webextension_events.js"]
tags = "webextensions"
+skip-if = ["os == 'android'"]
["test_webextension_icons.js"]
tags = "webextensions"
+skip-if = ["os == 'android'"]
["test_webextension_install.js"]
tags = "webextensions"
["test_webextension_install_syntax_error.js"]
tags = "webextensions"
+skip-if = ["os == 'android'"]
["test_webextension_langpack.js"]
tags = "webextensions"
+skip-if = ["os == 'android'"]
["test_webextension_theme.js"]
tags = "webextensions"
+skip-if = ["os == 'android'"]
diff --git a/toolkit/mozapps/extensions/test/xpinstall/browser_required_useractivation.js b/toolkit/mozapps/extensions/test/xpinstall/browser_required_useractivation.js
index 6c8894699d..b74cff859f 100644
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_required_useractivation.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_required_useractivation.js
@@ -17,6 +17,7 @@ async function runTestCase(spawnArgs, spawnFn, { expectInstall, clickLink }) {
set: [
// Make use the user activation requirements is enabled while running this test.
["xpinstall.userActivation.required", true],
+ ["dom.security.https_first", false],
],
});
await BrowserTestUtils.withNewTab(TESTROOT, async browser => {