From 8dd16259287f58f9273002717ec4d27e97127719 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 07:43:14 +0200 Subject: Merging upstream version 127.0. Signed-off-by: Daniel Baumann --- .../mozapps/extensions/test/browser/browser.toml | 14 +- .../test/browser/browser_amo_abuse_report.js | 21 +- .../test/browser/browser_html_abuse_report.js | 1091 -------------------- .../browser/browser_html_abuse_report_dialog.js | 185 ---- .../browser/browser_html_detail_permissions.js | 44 +- .../test/browser/browser_html_detail_view.js | 6 +- .../test/browser/browser_html_discover_view.js | 7 +- .../test/browser/browser_html_message_bar.js | 185 ---- .../browser/browser_html_options_ui_dark_theme.js | 173 ++++ .../browser/browser_html_scroll_restoration.js | 14 +- .../test/browser/browser_webapi_abuse_report.js | 375 ------- .../extensions/test/browser/head_abuse_report.js | 492 +-------- .../extensions/test/xpcshell/test_AbuseReporter.js | 687 +----------- .../test/xpcshell/test_dictionary_webextension.js | 15 +- .../test/xpcshell/test_webextension_install.js | 196 +++- .../mozapps/extensions/test/xpcshell/xpcshell.toml | 199 +++- .../xpinstall/browser_required_useractivation.js | 1 + 17 files changed, 633 insertions(+), 3072 deletions(-) delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_html_abuse_report.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_html_abuse_report_dialog.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_html_message_bar.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_html_options_ui_dark_theme.js delete mode 100644 toolkit/mozapps/extensions/test/browser/browser_webapi_abuse_report.js (limited to 'toolkit/mozapps/extensions/test') 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: ["", "tabs", "webNavigation"], }); - } else { + } + if (manifest_version >= 3 && expectGranted) { + await runTest({ + extension: extensions["addon1@mochi.test"], + permissions: ["tabs", "webNavigation"], + optional_permissions: [""], + optional_enabled: [""], + }); + } + 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": ` + `, + "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 + // at about:addons. In that case, the background color of the container + // element (i.e. the ) 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) { - // 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")) { + // 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 => { -- cgit v1.2.3