diff options
Diffstat (limited to 'browser/base/content/test')
50 files changed, 1453 insertions, 1580 deletions
diff --git a/browser/base/content/test/about/browser.toml b/browser/base/content/test/about/browser.toml index 900c6b7140..98961200a0 100644 --- a/browser/base/content/test/about/browser.toml +++ b/browser/base/content/test/about/browser.toml @@ -34,7 +34,8 @@ support-files = [ ["browser_aboutHome_search_suggestion.js"] skip-if = [ "os == 'mac'", - "os == 'linux' && (!debug || bits == 64)", + "os == 'linux' && os_version == '18.04' && !debug", + "os == 'linux' && os_version == '18.04' && bits == 64", "win10_2009 && bits == 64 && !debug", # Bug 1399648, bug 1402502 ] @@ -75,7 +76,7 @@ skip-if = ["tsan"] # Bug 1676326, highly frequent on TSan ["browser_aboutStopReload.js"] ["browser_aboutSupport.js"] -skip-if = ["os == 'linux' && bits == 64 && asan && !debug"] # Bug 1713368 +skip-if = ["os == 'linux' && os_version == '18.04' && asan"] # Bug 1713368 ["browser_aboutSupport_newtab_security_state.js"] @@ -83,6 +84,9 @@ skip-if = ["os == 'linux' && bits == 64 && asan && !debug"] # Bug 1713368 skip-if = ["os == 'android'"] ["browser_bug435325.js"] -skip-if = ["verify && !debug && os == 'mac'"] +skip-if = [ + "apple_catalina && !debug && verify", + "apple_silicon && !debug && verify", +] ["browser_bug633691.js"] diff --git a/browser/base/content/test/about/browser_aboutNetError.js b/browser/base/content/test/about/browser_aboutNetError.js index 8222a0f6e8..9131f5e696 100644 --- a/browser/base/content/test/about/browser_aboutNetError.js +++ b/browser/base/content/test/about/browser_aboutNetError.js @@ -25,6 +25,38 @@ function resetPrefs() { Services.prefs.clearUserPref("browser.fixup.alternate.enabled"); } +async function resetTelemetry() { + Services.telemetry.clearEvents(); + await TestUtils.waitForCondition(() => { + let events = Services.telemetry.snapshotEvents( + Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, + true + ).content; + return !events || !events.length; + }); + Services.telemetry.setEventRecordingEnabled("security.ui.tlserror", true); +} + +async function checkTelemetry(errorString) { + let loadEvent = await TestUtils.waitForCondition(() => { + let events = Services.telemetry.snapshotEvents( + Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, + true + ).content; + return events?.find(e => e[1] == "security.ui.tlserror" && e[2] == "load"); + }, "recorded telemetry for the load"); + loadEvent.shift(); + Assert.deepEqual(loadEvent, [ + "security.ui.tlserror", + "load", + "abouttlserror", + errorString, + { + is_frame: "false", + }, + ]); +} + add_task(async function resetToDefaultConfig() { info( "Change TLS config to cause page load to fail, check that reset button is shown and that it works" @@ -34,6 +66,8 @@ add_task(async function resetToDefaultConfig() { Services.prefs.setIntPref("security.tls.version.min", 1); // TLS 1.0 Services.prefs.setIntPref("security.tls.version.max", 1); + await resetTelemetry(); + let browser; let pageLoaded; await BrowserTestUtils.openNewForegroundTab( @@ -49,6 +83,8 @@ add_task(async function resetToDefaultConfig() { info("Loading and waiting for the net error"); await pageLoaded; + await checkTelemetry("SSL_ERROR_PROTOCOL_VERSION_ALERT"); + // Setup an observer for the target page. const finalLoadComplete = BrowserTestUtils.browserLoaded( browser, @@ -92,6 +128,8 @@ add_task(async function checkLearnMoreLink() { Services.prefs.setIntPref("security.tls.version.min", 3); Services.prefs.setIntPref("security.tls.version.max", 4); + await resetTelemetry(); + let browser; let pageLoaded; await BrowserTestUtils.openNewForegroundTab( @@ -107,6 +145,8 @@ add_task(async function checkLearnMoreLink() { info("Loading and waiting for the net error"); await pageLoaded; + await checkTelemetry("SSL_ERROR_PROTOCOL_VERSION_ALERT"); + const baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL"); await SpecialPowers.spawn(browser, [baseURL], function (_baseURL) { @@ -206,6 +246,8 @@ add_task(async function checkDomainCorrection() { // Test that ciphersuites that use 3DES (namely, TLS_RSA_WITH_3DES_EDE_CBC_SHA) // can only be enabled when deprecated TLS is enabled. add_task(async function onlyAllow3DESWithDeprecatedTLS() { + await resetTelemetry(); + // By default, connecting to a server that only uses 3DES should fail. await BrowserTestUtils.withNewTab( { gBrowser, url: "about:blank" }, @@ -215,6 +257,8 @@ add_task(async function onlyAllow3DESWithDeprecatedTLS() { } ); + await checkTelemetry("SSL_ERROR_NO_CYPHER_OVERLAP"); + // Enabling deprecated TLS should also enable 3DES. Services.prefs.setBoolPref("security.tls.version.enable-deprecated", true); await BrowserTestUtils.withNewTab( diff --git a/browser/base/content/test/contextMenu/browser_bug1798178.js b/browser/base/content/test/contextMenu/browser_bug1798178.js index 529665a6f9..de8bab1820 100644 --- a/browser/base/content/test/contextMenu/browser_bug1798178.js +++ b/browser/base/content/test/contextMenu/browser_bug1798178.js @@ -15,7 +15,7 @@ const TEST_URL = ) + "file_bug1798178.html"; let MockFilePicker = SpecialPowers.MockFilePicker; -MockFilePicker.init(window); +MockFilePicker.init(window.browsingContext); function createTemporarySaveDirectory() { let saveDir = Services.dirsvc.get("TmpD", Ci.nsIFile); diff --git a/browser/base/content/test/contextMenu/browser_contextmenu_save_blocked.js b/browser/base/content/test/contextMenu/browser_contextmenu_save_blocked.js index 5064d9a316..062fbeac08 100644 --- a/browser/base/content/test/contextMenu/browser_contextmenu_save_blocked.js +++ b/browser/base/content/test/contextMenu/browser_contextmenu_save_blocked.js @@ -4,7 +4,7 @@ "use strict"; var MockFilePicker = SpecialPowers.MockFilePicker; -MockFilePicker.init(window); +MockFilePicker.init(window.browsingContext); function mockPromptService() { let { prompt } = Services; diff --git a/browser/base/content/test/forms/browser.toml b/browser/base/content/test/forms/browser.toml index 33d73ba8bf..95b666369e 100644 --- a/browser/base/content/test/forms/browser.toml +++ b/browser/base/content/test/forms/browser.toml @@ -1,5 +1,5 @@ [DEFAULT] -prefs = ["gfx.font_loader.delay=0", "dom.select.showPicker.enabled=true"] +prefs = ["gfx.font_loader.delay=0", "dom.select.showPicker.enabled=true", "font.minimum-size.x-western=9"] support-files = ["head.js"] ["browser_selectpopup.js"] @@ -18,6 +18,8 @@ skip-if = ["os == 'linux'"] # Bug 1329991 - test fails intermittently on Linux b ["browser_selectpopup_large.js"] +["browser_selectpopup_minFontSize.js"] + ["browser_selectpopup_searchfocus.js"] fail-if = ["a11y_checks"] # Bug 1854233 input may not be labeled diff --git a/browser/base/content/test/forms/browser_selectpopup_minFontSize.js b/browser/base/content/test/forms/browser_selectpopup_minFontSize.js new file mode 100644 index 0000000000..d240c2d2d0 --- /dev/null +++ b/browser/base/content/test/forms/browser_selectpopup_minFontSize.js @@ -0,0 +1,38 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// NOTE that this test expects "font.minimum-size.x-western=9" to be set +// in the manifest. + +const PAGE = ` +<!doctype html> +<body lang="en-US"> +<select> + <option style="font-size:24px">A</option> + <option style="font-size:6px">BCD</option> +</select> +`; + +add_task(async function () { + const url = "data:text/html," + encodeURI(PAGE); + await BrowserTestUtils.withNewTab( + { + gBrowser, + url, + }, + async function (browser) { + let popup = await openSelectPopup("click"); + let menuitems = popup.querySelectorAll("menuitem"); + is( + getComputedStyle(menuitems[0]).fontSize, + "24px", + "font-size should be honored" + ); + is( + getComputedStyle(menuitems[1]).fontSize, + "9px", + "minimum font-size should be honored" + ); + } + ); +}); diff --git a/browser/base/content/test/general/browser_beforeunload_duplicate_dialogs.js b/browser/base/content/test/general/browser_beforeunload_duplicate_dialogs.js index 8a77f01ce4..8eb07a863a 100644 --- a/browser/base/content/test/general/browser_beforeunload_duplicate_dialogs.js +++ b/browser/base/content/test/general/browser_beforeunload_duplicate_dialogs.js @@ -1,36 +1,11 @@ const TEST_PAGE = "http://mochi.test:8888/browser/browser/base/content/test/general/file_double_close_tab.html"; -const CONTENT_PROMPT_SUBDIALOG = Services.prefs.getBoolPref( - "prompts.contentPromptSubDialog", - false -); - var expectingDialog = false; var wantToClose = true; var resolveDialogPromise; -function onTabModalDialogLoaded(node) { - ok( - !CONTENT_PROMPT_SUBDIALOG, - "Should not be using content prompt subdialogs." - ); - ok(expectingDialog, "Should be expecting this dialog."); - expectingDialog = false; - if (wantToClose) { - // This accepts the dialog, closing it - node.querySelector(".tabmodalprompt-button0").click(); - } else { - // This keeps the page open - node.querySelector(".tabmodalprompt-button1").click(); - } - if (resolveDialogPromise) { - resolveDialogPromise(); - } -} - function onCommonDialogLoaded(promptWindow) { - ok(CONTENT_PROMPT_SUBDIALOG, "Should be using content prompt subdialogs."); ok(expectingDialog, "Should be expecting this dialog."); expectingDialog = false; let dialog = promptWindow.Dialog; @@ -51,11 +26,9 @@ SpecialPowers.pushPrefEnv({ }); // Listen for the dialog being created -Services.obs.addObserver(onTabModalDialogLoaded, "tabmodal-dialog-loaded"); Services.obs.addObserver(onCommonDialogLoaded, "common-dialog-loaded"); registerCleanupFunction(() => { Services.prefs.clearUserPref("browser.tabs.warnOnClose"); - Services.obs.removeObserver(onTabModalDialogLoaded, "tabmodal-dialog-loaded"); Services.obs.removeObserver(onCommonDialogLoaded, "common-dialog-loaded"); }); diff --git a/browser/base/content/test/general/browser_bug676619.js b/browser/base/content/test/general/browser_bug676619.js index 24d8d88447..80bbce8cb0 100644 --- a/browser/base/content/test/general/browser_bug676619.js +++ b/browser/base/content/test/general/browser_bug676619.js @@ -1,5 +1,5 @@ var MockFilePicker = SpecialPowers.MockFilePicker; -MockFilePicker.init(window); +MockFilePicker.init(window.browsingContext); function waitForNewWindow() { return new Promise(resolve => { diff --git a/browser/base/content/test/general/browser_double_close_tab.js b/browser/base/content/test/general/browser_double_close_tab.js index 554aeb8077..f5f2f1b6c7 100644 --- a/browser/base/content/test/general/browser_double_close_tab.js +++ b/browser/base/content/test/general/browser_double_close_tab.js @@ -4,24 +4,15 @@ const TEST_PAGE = "http://mochi.test:8888/browser/browser/base/content/test/general/file_double_close_tab.html"; var testTab; -const CONTENT_PROMPT_SUBDIALOG = Services.prefs.getBoolPref( - "prompts.contentPromptSubDialog", - false -); - function waitForDialog(callback) { function onDialogLoaded(nodeOrDialogWindow) { - let node = CONTENT_PROMPT_SUBDIALOG - ? nodeOrDialogWindow.document.querySelector("dialog") - : nodeOrDialogWindow; - Services.obs.removeObserver(onDialogLoaded, "tabmodal-dialog-loaded"); + let node = nodeOrDialogWindow.document.querySelector("dialog"); Services.obs.removeObserver(onDialogLoaded, "common-dialog-loaded"); // Allow dialog's onLoad call to run to completion Promise.resolve().then(() => callback(node)); } // Listen for the dialog being created - Services.obs.addObserver(onDialogLoaded, "tabmodal-dialog-loaded"); Services.obs.addObserver(onDialogLoaded, "common-dialog-loaded"); } @@ -35,9 +26,7 @@ function waitForDialogDestroyed(node, callback) { }); observer.observe(node.parentNode, { childList: true }); - if (CONTENT_PROMPT_SUBDIALOG) { - node.ownerGlobal.addEventListener("unload", done); - } + node.ownerGlobal.addEventListener("unload", done); let failureTimeout = setTimeout(function () { ok(false, "Dialog should have been destroyed"); @@ -49,12 +38,8 @@ function waitForDialogDestroyed(node, callback) { observer.disconnect(); observer = null; - if (CONTENT_PROMPT_SUBDIALOG) { - node.ownerGlobal.removeEventListener("unload", done); - SimpleTest.executeSoon(callback); - } else { - callback(); - } + node.ownerGlobal.removeEventListener("unload", done); + SimpleTest.executeSoon(callback); } } @@ -76,23 +61,12 @@ add_task(async function () { let doCompletion = () => setTimeout(resolveOuter, 0); info("Now checking if dialog is destroyed"); - if (CONTENT_PROMPT_SUBDIALOG) { - ok( - !dialogNode.ownerGlobal || dialogNode.ownerGlobal.closed, - "onbeforeunload dialog should be gone." - ); - if (dialogNode.ownerGlobal && !dialogNode.ownerGlobal.closed) { - dialogNode.acceptDialog(); - } - } else { - ok(!dialogNode.parentNode, "onbeforeunload dialog should be gone."); - if (dialogNode.parentNode) { - // Failed to remove onbeforeunload dialog, so do it ourselves: - let leaveBtn = dialogNode.querySelector(".tabmodalprompt-button0"); - waitForDialogDestroyed(dialogNode, doCompletion); - EventUtils.synthesizeMouseAtCenter(leaveBtn, {}); - return; - } + ok( + !dialogNode.ownerGlobal || dialogNode.ownerGlobal.closed, + "onbeforeunload dialog should be gone." + ); + if (dialogNode.ownerGlobal && !dialogNode.ownerGlobal.closed) { + dialogNode.acceptDialog(); } doCompletion(); diff --git a/browser/base/content/test/general/browser_minimize.js b/browser/base/content/test/general/browser_minimize.js index a57fea079c..3919cd7d77 100644 --- a/browser/base/content/test/general/browser_minimize.js +++ b/browser/base/content/test/general/browser_minimize.js @@ -12,26 +12,57 @@ add_task(async function () { ok(isActive(), "Docshell should be active when starting the test"); ok(!document.hidden, "Top level window should be visible"); + // When we show or hide the window (including by minimization), + // there are 2 signifiers that the process is complete: the + // sizemodechange event, and the browsing context becoming active + // or inactive. There is another signifier, the + // occlusionstatechange event, but whether or not that event + // is sent is platform-dependent, so it's not very useful. The + // safest way to check for stable state is to build promises + // around sizemodechange and browsing context active and then + // wait for them all to complete, and that's what we do here. info("Calling window.minimize"); let promiseSizeModeChange = BrowserTestUtils.waitForEvent( window, "sizemodechange" + ).then( + () => ok(true, "Got sizemodechange."), + () => ok(false, "Rejected sizemodechange.") + ); + let promiseBrowserInactive = BrowserTestUtils.waitForCondition( + () => !isActive(), + "Docshell should be inactive." + ).then( + () => ok(true, "Got inactive."), + () => ok(false, "Rejected inactive.") ); window.minimize(); - await promiseSizeModeChange; - ok(!isActive(), "Docshell should be Inactive"); + await Promise.all([promiseSizeModeChange, promiseBrowserInactive]); ok(document.hidden, "Top level window should be hidden"); + // When we restore the window from minimization, we have the + // same concerns as above, so prepare our promises. info("Calling window.restore"); promiseSizeModeChange = BrowserTestUtils.waitForEvent( window, "sizemodechange" + ).then( + () => ok(true, "Got sizemodechange."), + () => ok(false, "Rejected sizemodechange.") + ); + let promiseBrowserActive = BrowserTestUtils.waitForCondition( + () => isActive(), + "Docshell should be active." + ).then( + () => ok(true, "Got active."), + () => ok(false, "Rejected active.") ); window.restore(); + // On Ubuntu `window.restore` doesn't seem to work, use a timer to make the // test fail faster and more cleanly than with a test timeout. await Promise.race([ - promiseSizeModeChange, + Promise.all([promiseSizeModeChange, promiseBrowserActive]), new Promise((resolve, reject) => // eslint-disable-next-line mozilla/no-arbitrary-setTimeout setTimeout(() => { @@ -39,11 +70,5 @@ add_task(async function () { }, 5000) ), ]); - // The sizemodechange event can sometimes be fired before the - // occlusionstatechange event, especially in chaos mode. - if (window.isFullyOccluded) { - await BrowserTestUtils.waitForEvent(window, "occlusionstatechange"); - } - ok(isActive(), "Docshell should be active again"); ok(!document.hidden, "Top level window should be visible"); }); diff --git a/browser/base/content/test/general/browser_save_link-perwindowpb.js b/browser/base/content/test/general/browser_save_link-perwindowpb.js index b018212280..234813ca2c 100644 --- a/browser/base/content/test/general/browser_save_link-perwindowpb.js +++ b/browser/base/content/test/general/browser_save_link-perwindowpb.js @@ -2,7 +2,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ var MockFilePicker = SpecialPowers.MockFilePicker; -MockFilePicker.init(window); +MockFilePicker.init(window.browsingContext); // Trigger a save of a link in public mode, then trigger an identical save // in private mode and ensure that the second request is differentiated from @@ -14,7 +14,7 @@ function triggerSave(aWindow, aCallback) { let testBrowser = aWindow.gBrowser.selectedBrowser; // This page sets a cookie if and only if a cookie does not exist yet let testURI = - "http://mochi.test:8888/browser/browser/base/content/test/general/bug792517-2.html"; + "https://example.com/browser/browser/base/content/test/general/bug792517-2.html"; BrowserTestUtils.startLoadingURIString(testBrowser, testURI); BrowserTestUtils.browserLoaded(testBrowser, false, testURI).then(() => { waitForFocus(function () { @@ -132,7 +132,7 @@ function test() { info("onExamineResponse with " + channel.URI.spec); if ( channel.URI.spec != - "http://mochi.test:8888/browser/browser/base/content/test/general/bug792517.sjs" + "https://example.com/browser/browser/base/content/test/general/bug792517.sjs" ) { info("returning"); return; @@ -158,7 +158,7 @@ function test() { info("onModifyRequest with " + channel.URI.spec); if ( channel.URI.spec != - "http://mochi.test:8888/browser/browser/base/content/test/general/bug792517.sjs" + "https://example.com/browser/browser/base/content/test/general/bug792517.sjs" ) { return; } diff --git a/browser/base/content/test/general/browser_save_link_when_window_navigates.js b/browser/base/content/test/general/browser_save_link_when_window_navigates.js index e7507fcbb0..65daef5f1b 100644 --- a/browser/base/content/test/general/browser_save_link_when_window_navigates.js +++ b/browser/base/content/test/general/browser_save_link_when_window_navigates.js @@ -2,7 +2,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ var MockFilePicker = SpecialPowers.MockFilePicker; -MockFilePicker.init(window); +MockFilePicker.init(window.browsingContext); const SAVE_PER_SITE_PREF = "browser.download.lastDir.savePerSite"; const ALWAYS_DOWNLOAD_DIR_PREF = "browser.download.useDownloadDir"; @@ -36,7 +36,7 @@ function triggerSave(aWindow, aCallback) { var fileName; let testBrowser = aWindow.gBrowser.selectedBrowser; let testURI = - "http://mochi.test:8888/browser/browser/base/content/test/general/navigating_window_with_download.html"; + "https://example.com/browser/browser/base/content/test/general/navigating_window_with_download.html"; // Only observe the UTC dialog if it's enabled by pref if (Services.prefs.getBoolPref(ALWAYS_ASK_PREF)) { diff --git a/browser/base/content/test/general/browser_save_private_link_perwindowpb.js b/browser/base/content/test/general/browser_save_private_link_perwindowpb.js index 8ede97e640..42632bdc5a 100644 --- a/browser/base/content/test/general/browser_save_private_link_perwindowpb.js +++ b/browser/base/content/test/general/browser_save_private_link_perwindowpb.js @@ -43,7 +43,7 @@ function promiseImageDownloaded() { return new Promise((resolve, reject) => { let fileName; let MockFilePicker = SpecialPowers.MockFilePicker; - MockFilePicker.init(window); + MockFilePicker.init(window.browsingContext); function onTransferComplete(downloadSuccess) { ok( diff --git a/browser/base/content/test/general/browser_save_video.js b/browser/base/content/test/general/browser_save_video.js index 276088fbb1..e9701d7023 100644 --- a/browser/base/content/test/general/browser_save_video.js +++ b/browser/base/content/test/general/browser_save_video.js @@ -2,7 +2,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ var MockFilePicker = SpecialPowers.MockFilePicker; -MockFilePicker.init(window); +MockFilePicker.init(window.browsingContext); /** * TestCase for bug 564387 @@ -14,7 +14,7 @@ add_task(async function () { let loadPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); BrowserTestUtils.startLoadingURIString( gBrowser, - "http://mochi.test:8888/browser/browser/base/content/test/general/web_video.html" + "https://example.com/browser/browser/base/content/test/general/web_video.html" ); await loadPromise; diff --git a/browser/base/content/test/general/browser_save_video_frame.js b/browser/base/content/test/general/browser_save_video_frame.js index 877c33bcd3..11fe3ac80e 100644 --- a/browser/base/content/test/general/browser_save_video_frame.js +++ b/browser/base/content/test/general/browser_save_video_frame.js @@ -49,7 +49,7 @@ function waitForTransferComplete() { */ add_task(async function () { let MockFilePicker = SpecialPowers.MockFilePicker; - MockFilePicker.init(window); + MockFilePicker.init(window.browsingContext); // Create the folder the video will be saved into. let destDir = createTemporarySaveDirectory(); diff --git a/browser/base/content/test/general/browser_visibleTabs_bookmarkAllPages.js b/browser/base/content/test/general/browser_visibleTabs_bookmarkAllPages.js index 2c0002fc44..2ec3b632f2 100644 --- a/browser/base/content/test/general/browser_visibleTabs_bookmarkAllPages.js +++ b/browser/base/content/test/general/browser_visibleTabs_bookmarkAllPages.js @@ -15,7 +15,9 @@ function test() { is(gBrowser.visibleTabs.length, 1, "Only one tab is visible"); - let uris = PlacesCommandHook.uniqueCurrentPages; + let uris = PlacesCommandHook.getUniquePages( + gBrowser.visibleTabs.filter(tab => !tab.pinned) + ); is(uris.length, 1, "Only one uri is returned"); is( diff --git a/browser/base/content/test/general/navigating_window_with_download.html b/browser/base/content/test/general/navigating_window_with_download.html index 6b0918941f..8649168cf5 100644 --- a/browser/base/content/test/general/navigating_window_with_download.html +++ b/browser/base/content/test/general/navigating_window_with_download.html @@ -2,6 +2,6 @@ <html> <head><title>This window will navigate while you're downloading something</title></head> <body> - <iframe src="http://mochi.test:8888/browser/browser/base/content/test/general/unknownContentType_file.pif"></iframe> + <iframe src="https://example.com/browser/browser/base/content/test/general/unknownContentType_file.pif"></iframe> </body> </html> diff --git a/browser/base/content/test/outOfProcess/browser_controller.js b/browser/base/content/test/outOfProcess/browser_controller.js index f9d9ca8c93..f3c0217b90 100644 --- a/browser/base/content/test/outOfProcess/browser_controller.js +++ b/browser/base/content/test/outOfProcess/browser_controller.js @@ -42,8 +42,19 @@ add_task(async function test_controllers_subframes() { gURLBar.focus(); + let canTabMoveFocusToRootElement = !SpecialPowers.getBoolPref( + "dom.disable_tab_focus_to_root_element" + ); for (let stepNum = 0; stepNum < browsingContexts.length; stepNum++) { - await keyAndUpdate(stepNum > 0 ? "VK_TAB" : "VK_F6", {}, 6); + let useTab = stepNum > 0; + // When canTabMoveFocusToRootElement is true, this kepress will move the + // focus to a root element, which will trigger an extra "select" command + // compare to the case when canTabMoveFocusToRootElement is false. + await keyAndUpdate( + useTab ? "VK_TAB" : "VK_F6", + {}, + canTabMoveFocusToRootElement ? 6 : 4 + ); // Since focus may be switching into a separate process here, // need to wait for the focus to have been updated. @@ -59,22 +70,35 @@ add_task(async function test_controllers_subframes() { goUpdateGlobalEditMenuItems(true); } - await SpecialPowers.spawn(browsingContexts[stepNum], [], () => { - // Both the tab key and document navigation with F6 will focus - // the root of the document within the frame. - let document = content.document; - Assert.equal( - document.activeElement, - document.documentElement, - "root focused" + await SpecialPowers.spawn( + browsingContexts[stepNum], + [{ canTabMoveFocusToRootElement, useTab }], + args => { + // Both the tab key and document navigation with F6 will focus + // the root of the document within the frame. + // When dom.disable_tab_focus_to_root_element is true, only F6 will do this. + let document = content.document; + let expectedElement = + args.canTabMoveFocusToRootElement || !args.useTab + ? document.documentElement + : document.getElementById("input"); + Assert.equal(document.activeElement, expectedElement, "root focused"); + } + ); + + if (canTabMoveFocusToRootElement || !useTab) { + // XXX Currently, Copy is always enabled when the root (not an editor element) + // is focused. Possibly that should only be true if a listener is present? + checkCommandState( + "step " + stepNum + " root focused", + false, + true, + false ); - }); - // XXX Currently, Copy is always enabled when the root (not an editor element) - // is focused. Possibly that should only be true if a listener is present? - checkCommandState("step " + stepNum + " root focused", false, true, false); - // Tab to the textbox. - await keyAndUpdate("VK_TAB", {}, 1); + // Tab to the textbox. + await keyAndUpdate("VK_TAB", {}, 1); + } if (AppConstants.platform != "macosx") { goUpdateGlobalEditMenuItems(true); diff --git a/browser/base/content/test/performance/browser_appmenu.js b/browser/base/content/test/performance/browser_appmenu.js index 37e7482c51..984d2b9fd8 100644 --- a/browser/base/content/test/performance/browser_appmenu.js +++ b/browser/base/content/test/performance/browser_appmenu.js @@ -21,15 +21,6 @@ const EXPECTED_APPMENU_OPEN_REFLOWS = [ "openPopup/this._openPopupPromise<@resource:///modules/PanelMultiView.sys.mjs", ], }, - - { - stack: [ - "_calculateMaxHeight@resource:///modules/PanelMultiView.sys.mjs", - "handleEvent@resource:///modules/PanelMultiView.sys.mjs", - ], - - maxCount: 7, // This number should only ever go down - never up. - }, ]; add_task(async function () { diff --git a/browser/base/content/test/performance/browser_startup_content_mainthreadio.js b/browser/base/content/test/performance/browser_startup_content_mainthreadio.js index e60b95bb3c..e267363064 100644 --- a/browser/base/content/test/performance/browser_startup_content_mainthreadio.js +++ b/browser/base/content/test/performance/browser_startup_content_mainthreadio.js @@ -152,6 +152,13 @@ const processes = { condition: WIN, stat: 1, }, + { + // We should remove this in bug 1882427 + path: "*screenshots@mozilla.org.xpi", + condition: true, + ignoreIfUnused: true, + close: 1, + }, ], }; diff --git a/browser/base/content/test/popupNotifications/browser_popupNotification_security_delay.js b/browser/base/content/test/popupNotifications/browser_popupNotification_security_delay.js index 4a9276512c..3b027bc1ef 100644 --- a/browser/base/content/test/popupNotifications/browser_popupNotification_security_delay.js +++ b/browser/base/content/test/popupNotifications/browser_popupNotification_security_delay.js @@ -5,6 +5,8 @@ const TEST_SECURITY_DELAY = 5000; +SimpleTest.requestCompleteLog(); + /** * Shows a test PopupNotification. */ @@ -400,3 +402,166 @@ add_task(async function test_notificationWindowMove() { // Reset window position window.moveTo(screenX, screenY); }); + +/** + * Tests that the security delay gets extended if a notification is shown during + * a full screen transition. + */ +add_task(async function test_notificationDuringFullScreenTransition() { + // Log full screen transition messages. + let loggingObserver = { + observe(subject, topic) { + info("Observed topic: " + topic); + }, + }; + Services.obs.addObserver(loggingObserver, "fullscreen-transition-start"); + Services.obs.addObserver(loggingObserver, "fullscreen-transition-end"); + // Unregister observers when the test ends: + registerCleanupFunction(() => { + Services.obs.removeObserver(loggingObserver, "fullscreen-transition-start"); + Services.obs.removeObserver(loggingObserver, "fullscreen-transition-end"); + }); + + if (Services.appinfo.OS == "Linux") { + ok( + "Skipping test on Linux because of disabled full screen transition in CI." + ); + return; + } + // Bug 1882527: Intermittent failures on macOS. + if (Services.appinfo.OS == "Darwin") { + ok("Skipping test on macOS because of intermittent failures."); + return; + } + + await BrowserTestUtils.withNewTab("https://example.com", async browser => { + await SpecialPowers.pushPrefEnv({ + set: [ + // Set a short security delay so we can observe it being extended. + ["security.notification_enable_delay", 1], + // Set a longer full screen exit transition so the test works on slow builds. + ["full-screen-api.transition-duration.leave", "1000 1000"], + // Waive the user activation requirement for full screen requests. + // The PoC this test is based on relies on spam clicking which grants + // user activation in the popup that requests full screen. + // This isn't reliable in automation. + ["full-screen-api.allow-trusted-requests-only", false], + // macOS native full screen is not affected by the full screen + // transition overlap. Test with the old full screen implementation. + ["full-screen-api.macos-native-full-screen", false], + ], + }); + + await ensureSecurityDelayReady(); + + ok( + !PopupNotifications.isPanelOpen, + "PopupNotification panel should not be open initially." + ); + + info("Open a notification."); + let popupShownPromise = waitForNotificationPanel(); + showNotification(); + await popupShownPromise; + ok( + PopupNotifications.isPanelOpen, + "PopupNotification should be open after show call." + ); + + let notification = PopupNotifications.getNotification("foo", browser); + is(notification?.id, "foo", "There should be a notification with id foo"); + + info( + "Open a new tab via window.open, enter full screen and remove the tab." + ); + + // There are two transitions, one for full screen entry and one for full screen exit. + let transitionStartCount = 0; + let transitionEndCount = 0; + let promiseFullScreenTransitionStart = TestUtils.topicObserved( + "fullscreen-transition-start", + () => { + transitionStartCount++; + return transitionStartCount == 2; + } + ); + let promiseFullScreenTransitionEnd = TestUtils.topicObserved( + "fullscreen-transition-end", + () => { + transitionEndCount++; + return transitionEndCount == 2; + } + ); + let notificationShownPromise = waitForNotificationPanel(); + + await SpecialPowers.spawn(browser, [], () => { + // Use eval to execute in the privilege context of the website. + content.eval(` + let button = document.createElement("button"); + button.id = "triggerBtn"; + button.innerText = "Open Popup"; + button.addEventListener("click", () => { + let popup = window.open("about:blank"); + popup.document.write( + "<script>setTimeout(() => document.documentElement.requestFullscreen(), 500)</script>" + ); + popup.document.write( + "<script>setTimeout(() => window.close(), 1500)</script>" + ); + }); + // Insert button at the top so the synthesized click works. Otherwise + // the button may be outside of the viewport. + document.body.prepend(button); + `); + }); + + let timeClick = performance.now(); + await BrowserTestUtils.synthesizeMouseAtCenter("#triggerBtn", {}, browser); + + info("Wait for the exit transition to start. It's the second transition."); + await promiseFullScreenTransitionStart; + info("Full screen transition start"); + ok(true, "Full screen transition started"); + ok( + window.isInFullScreenTransition, + "Full screen transition is still running." + ); + + info( + "Wait for notification to re-show on tab switch, after the popup has been closed" + ); + await notificationShownPromise; + ok( + window.isInFullScreenTransition, + "Full screen transition is still running." + ); + info( + "about to trigger notification. time between btn click and notification show: " + + (performance.now() - timeClick) + ); + + info( + "Trigger main action via button click during the extended security delay." + ); + triggerMainCommand(PopupNotifications.panel); + + await new Promise(resolve => setTimeout(resolve, 0)); + + ok( + PopupNotifications.isPanelOpen, + "PopupNotification should still be open." + ); + notification = PopupNotifications.getNotification( + "foo", + gBrowser.selectedBrowser + ); + ok( + notification, + "Notification should still be open because we clicked during the security delay." + ); + + info("Wait for full screen transition end."); + await promiseFullScreenTransitionEnd; + info("Full screen transition end"); + }); +}); diff --git a/browser/base/content/test/popups/browser_popup_blocker.js b/browser/base/content/test/popups/browser_popup_blocker.js index bfda12331e..d2e182b366 100644 --- a/browser/base/content/test/popups/browser_popup_blocker.js +++ b/browser/base/content/test/popups/browser_popup_blocker.js @@ -34,9 +34,18 @@ add_task(async function test_maximum_reported_blocks() { ); // Wait for the popup-blocked notification. - let notification = await TestUtils.waitForCondition(() => - gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked") - ); + let notification = await TestUtils.waitForCondition(() => { + let tempNotif = gBrowser + .getNotificationBox() + .getNotificationWithValue("popup-blocked"); + + // The textContent in the notification object is contains + // blank spaces as placeholder if there is no value in it + if (tempNotif?.messageText.textContent.trim().length) { + return tempNotif; + } + return false; + }); // Slightly hacky way to ensure we show the correct message in this case. ok( diff --git a/browser/base/content/test/privateBrowsing/browser_private_browsing_simplified_ui.js b/browser/base/content/test/privateBrowsing/browser_private_browsing_simplified_ui.js index 162bf7ab5a..c52ed4187a 100644 --- a/browser/base/content/test/privateBrowsing/browser_private_browsing_simplified_ui.js +++ b/browser/base/content/test/privateBrowsing/browser_private_browsing_simplified_ui.js @@ -30,19 +30,4 @@ add_task(async function check_for_simplified_pbm_ui() { ); await BrowserTestUtils.closeWindow(pbmWindow); - await SpecialPowers.pushPrefEnv({ - set: [["browser.toolbars.bookmarks.showInPrivateBrowsing", true]], - }); - pbmWindow = await BrowserTestUtils.openNewBrowserWindow({ - private: true, - }); - bookmarksBar = pbmWindow.document.getElementById("PersonalToolbar"); - console.info(bookmarksBar.getAttribute("collapsed")); - Assert.equal( - bookmarksBar.getAttribute("collapsed").toString(), - "false", - "Bookmarks bar is visible in PBM window when showInPrivateBrowsing pref is true" - ); - - await BrowserTestUtils.closeWindow(pbmWindow); }); diff --git a/browser/base/content/test/protectionsUI/browser.toml b/browser/base/content/test/protectionsUI/browser.toml index 10611cbe8c..f3c64eb67f 100644 --- a/browser/base/content/test/protectionsUI/browser.toml +++ b/browser/base/content/test/protectionsUI/browser.toml @@ -59,13 +59,6 @@ https_first_disabled = true ["browser_protectionsUI_pbmode_exceptions.js"] https_first_disabled = true -["browser_protectionsUI_report_breakage.js"] -https_first_disabled = true -skip-if = [ - "debug", # Bug 1546797 - "asan", -] - ["browser_protectionsUI_shield_visibility.js"] support-files = [ "sandboxed.html", diff --git a/browser/base/content/test/protectionsUI/browser_protectionsUI.js b/browser/base/content/test/protectionsUI/browser_protectionsUI.js index 98698e087e..5dc6acebf7 100644 --- a/browser/base/content/test/protectionsUI/browser_protectionsUI.js +++ b/browser/base/content/test/protectionsUI/browser_protectionsUI.js @@ -73,85 +73,16 @@ add_task(async function testToggleSwitch() { console.log(buttonEvents); is(buttonEvents.length, 1, "recorded telemetry for opening the popup"); - // Check the visibility of the "Site not working?" link. - ok( - BrowserTestUtils.isVisible( - gProtectionsHandler._protectionsPopupTPSwitchBreakageLink - ), - "The 'Site not working?' link should be visible." - ); - - // The 'Site Fixed?' link should be hidden. - ok( - BrowserTestUtils.isHidden( - gProtectionsHandler._protectionsPopupTPSwitchBreakageFixedLink - ), - "The 'Site Fixed?' link should be hidden." - ); - - // Navigate through the 'Site Not Working?' flow and back to the main view, - // checking for telemetry on the way. - let siteNotWorkingView = document.getElementById( - "protections-popup-siteNotWorkingView" - ); - let viewShown = BrowserTestUtils.waitForEvent( - siteNotWorkingView, - "ViewShown" - ); - gProtectionsHandler._protectionsPopupTPSwitchBreakageLink.click(); - await viewShown; - - checkClickTelemetry("sitenotworking_link"); - - let sendReportButton = document.getElementById( - "protections-popup-siteNotWorkingView-sendReport" - ); - let sendReportView = document.getElementById( - "protections-popup-sendReportView" - ); - viewShown = BrowserTestUtils.waitForEvent(sendReportView, "ViewShown"); - sendReportButton.click(); - await viewShown; - - checkClickTelemetry("send_report_link"); - - viewShown = BrowserTestUtils.waitForEvent(siteNotWorkingView, "ViewShown"); - sendReportView.querySelector(".subviewbutton-back").click(); - await viewShown; - - let mainView = document.getElementById("protections-popup-mainView"); - - viewShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown"); - siteNotWorkingView.querySelector(".subviewbutton-back").click(); - await viewShown; + let browserLoadedPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser); - ok( - gProtectionsHandler._protectionsPopupTPSwitch.hasAttribute("pressed"), - "TP Switch should be on" - ); let popuphiddenPromise = BrowserTestUtils.waitForEvent( gProtectionsHandler._protectionsPopup, "popuphidden" ); - let browserLoadedPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser); - await clickToggle(gProtectionsHandler._protectionsPopupTPSwitch); - - // The 'Site not working?' link should be hidden after clicking the TP switch. - ok( - BrowserTestUtils.isHidden( - gProtectionsHandler._protectionsPopupTPSwitchBreakageLink - ), - "The 'Site not working?' link should be hidden after TP switch turns to off." - ); - // Same for the 'Site Fixed?' link - ok( - BrowserTestUtils.isHidden( - gProtectionsHandler._protectionsPopupTPSwitchBreakageFixedLink - ), - "The 'Site Fixed?' link should be hidden." - ); + await clickToggle(gProtectionsHandler._protectionsPopupTPSwitch); await popuphiddenPromise; + checkClickTelemetry("etp_toggle_off"); // We need to wait toast's popup shown and popup hidden events. It won't fire @@ -164,41 +95,13 @@ add_task(async function testToggleSwitch() { // Wait until the ETP state confirmation toast is shown and hides itself. await toastShown; + // Re-open the protections panel and confirm that the toggle is off, then toggle it back on. await openProtectionsPanel(); ok( !gProtectionsHandler._protectionsPopupTPSwitch.hasAttribute("pressed"), "TP Switch should be off" ); - // The 'Site not working?' link should be hidden if the TP is off. - ok( - BrowserTestUtils.isHidden( - gProtectionsHandler._protectionsPopupTPSwitchBreakageLink - ), - "The 'Site not working?' link should be hidden if TP is off." - ); - - // The 'Site Fixed?' link should be shown if TP is off. - ok( - BrowserTestUtils.isVisible( - gProtectionsHandler._protectionsPopupTPSwitchBreakageFixedLink - ), - "The 'Site Fixed?' link should be visible." - ); - - // Check telemetry for 'Site Fixed?' link. - viewShown = BrowserTestUtils.waitForEvent(sendReportView, "ViewShown"); - gProtectionsHandler._protectionsPopupTPSwitchBreakageFixedLink.click(); - await viewShown; - - checkClickTelemetry("sitenotworking_link", "sitefixed"); - - viewShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown"); - sendReportView.querySelector(".subviewbutton-back").click(); - await viewShown; - - // Click the TP switch again and check the visibility of the 'Site not - // Working?'. It should be hidden after toggling the TP switch. browserLoadedPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser); popuphiddenPromise = BrowserTestUtils.waitForEvent( @@ -208,20 +111,6 @@ add_task(async function testToggleSwitch() { await clickToggle(gProtectionsHandler._protectionsPopupTPSwitch); - ok( - BrowserTestUtils.isHidden( - gProtectionsHandler._protectionsPopupTPSwitchBreakageLink - ), - `The 'Site not working?' link should be still hidden after toggling TP - switch to on from off.` - ); - ok( - BrowserTestUtils.isHidden( - gProtectionsHandler._protectionsPopupTPSwitchBreakageFixedLink - ), - "The 'Site Fixed?' link should be hidden." - ); - // Wait for the protections panel to be hidden as the result of the ETP toggle // on action. await popuphiddenPromise; diff --git a/browser/base/content/test/protectionsUI/browser_protectionsUI_report_breakage.js b/browser/base/content/test/protectionsUI/browser_protectionsUI_report_breakage.js deleted file mode 100644 index 2ae0d5c9d9..0000000000 --- a/browser/base/content/test/protectionsUI/browser_protectionsUI_report_breakage.js +++ /dev/null @@ -1,415 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -const TRACKING_PAGE = - // eslint-disable-next-line @microsoft/sdl/no-insecure-url - "http://tracking.example.org/browser/browser/base/content/test/protectionsUI/trackingPage.html"; -const BENIGN_PAGE = - // eslint-disable-next-line @microsoft/sdl/no-insecure-url - "http://tracking.example.org/browser/browser/base/content/test/protectionsUI/benignPage.html"; -const COOKIE_PAGE = - // eslint-disable-next-line @microsoft/sdl/no-insecure-url - "http://not-tracking.example.com/browser/browser/base/content/test/protectionsUI/cookiePage.html"; - -const CM_PREF = "privacy.trackingprotection.cryptomining.enabled"; -const FP_PREF = "privacy.trackingprotection.fingerprinting.enabled"; -const TP_PREF = "privacy.trackingprotection.enabled"; -const CB_PREF = "network.cookie.cookieBehavior"; -const GPC_PREF = "privacy.globalprivacycontrol.enabled"; - -const PREF_REPORT_BREAKAGE_URL = "browser.contentblocking.reportBreakage.url"; - -let { HttpServer } = ChromeUtils.importESModule( - "resource://testing-common/httpd.sys.mjs" -); -let { CommonUtils } = ChromeUtils.importESModule( - "resource://services-common/utils.sys.mjs" -); -let { Preferences } = ChromeUtils.importESModule( - "resource://gre/modules/Preferences.sys.mjs" -); - -add_setup(async function () { - await UrlClassifierTestUtils.addTestTrackers(); - - // Disable Report Broken Site, as it hides "Site not working?" when enabled. - await SpecialPowers.pushPrefEnv({ - set: [["ui.new-webcompat-reporter.enabled", false]], - }); - - registerCleanupFunction(() => { - // Clear prefs that are touched in this test again for sanity. - Services.prefs.clearUserPref(TP_PREF); - Services.prefs.clearUserPref(CB_PREF); - Services.prefs.clearUserPref(FP_PREF); - Services.prefs.clearUserPref(CM_PREF); - Services.prefs.clearUserPref(GPC_PREF); - Services.prefs.clearUserPref(PREF_REPORT_BREAKAGE_URL); - - UrlClassifierTestUtils.cleanupTestTrackers(); - }); - - await SpecialPowers.pushPrefEnv({ - set: [ - [ - "urlclassifier.features.fingerprinting.blacklistHosts", - "fingerprinting.example.com", - ], - [ - "urlclassifier.features.fingerprinting.annotate.blacklistHosts", - "fingerprinting.example.com", - ], - ["privacy.trackingprotection.cryptomining.enabled", true], - [ - "urlclassifier.features.cryptomining.blacklistHosts", - "cryptomining.example.com", - ], - [ - "urlclassifier.features.cryptomining.annotate.blacklistHosts", - "cryptomining.example.com", - ], - ["privacy.globalprivacycontrol.enabled", true], - ], - }); -}); - -add_task(async function testReportBreakageCancel() { - Services.prefs.setBoolPref(TP_PREF, true); - - await BrowserTestUtils.withNewTab(TRACKING_PAGE, async function () { - await openProtectionsPanel(); - await TestUtils.waitForCondition(() => - gProtectionsHandler._protectionsPopup.hasAttribute("blocking") - ); - - let siteNotWorkingButton = document.getElementById( - "protections-popup-tp-switch-breakage-link" - ); - ok( - BrowserTestUtils.isVisible(siteNotWorkingButton), - "site not working button is visible" - ); - let siteNotWorkingView = document.getElementById( - "protections-popup-siteNotWorkingView" - ); - let viewShown = BrowserTestUtils.waitForEvent( - siteNotWorkingView, - "ViewShown" - ); - siteNotWorkingButton.click(); - await viewShown; - - let sendReportButton = document.getElementById( - "protections-popup-siteNotWorkingView-sendReport" - ); - let sendReportView = document.getElementById( - "protections-popup-sendReportView" - ); - viewShown = BrowserTestUtils.waitForEvent(sendReportView, "ViewShown"); - sendReportButton.click(); - await viewShown; - - ok(true, "Report breakage view was shown"); - - viewShown = BrowserTestUtils.waitForEvent(siteNotWorkingView, "ViewShown"); - let cancelButton = document.getElementById( - "protections-popup-sendReportView-cancel" - ); - cancelButton.click(); - await viewShown; - - ok(true, "Main view was shown"); - }); - - Services.prefs.clearUserPref(TP_PREF); -}); - -add_task(async function testReportBreakageSiteException() { - Services.prefs.setBoolPref(TP_PREF, true); - - let url = TRACKING_PAGE + "?a=b&1=abc&unicode=🦊"; - - await BrowserTestUtils.withNewTab(url, async browser => { - let loaded = BrowserTestUtils.browserLoaded(browser, false); - gProtectionsHandler.disableForCurrentPage(); - await loaded; - - await openProtectionsPanel(); - - let siteFixedButton = document.getElementById( - "protections-popup-tp-switch-breakage-fixed-link" - ); - ok( - BrowserTestUtils.isVisible(siteFixedButton), - "site fixed button is visible" - ); - let sendReportView = document.getElementById( - "protections-popup-sendReportView" - ); - let viewShown = BrowserTestUtils.waitForEvent(sendReportView, "ViewShown"); - siteFixedButton.click(); - await viewShown; - - ok(true, "Report breakage view was shown"); - - await testReportBreakageSubmit( - TRACKING_PAGE, - "trackingprotection", - false, - true - ); - - // Pass false for shouldReload - there's no need since the tab is going away. - gProtectionsHandler.enableForCurrentPage(false); - }); - - Services.prefs.clearUserPref(TP_PREF); -}); - -add_task(async function testNoTracking() { - await BrowserTestUtils.withNewTab(BENIGN_PAGE, async function () { - await openProtectionsPanel(); - - let siteNotWorkingButton = document.getElementById( - "protections-popup-tp-switch-breakage-link" - ); - ok( - BrowserTestUtils.isHidden(siteNotWorkingButton), - "site not working button is not visible" - ); - }); -}); - -add_task(async function testReportBreakageError() { - Services.prefs.setBoolPref(TP_PREF, true); - // Make sure that we correctly strip the query. - let url = TRACKING_PAGE + "?a=b&1=abc&unicode=🦊"; - await BrowserTestUtils.withNewTab(url, async function () { - await openAndTestReportBreakage(TRACKING_PAGE, "trackingprotection", true); - }); - - Services.prefs.clearUserPref(TP_PREF); -}); - -add_task(async function testTP() { - Services.prefs.setBoolPref(TP_PREF, true); - // Make sure that we correctly strip the query. - let url = TRACKING_PAGE + "?a=b&1=abc&unicode=🦊"; - await BrowserTestUtils.withNewTab(url, async function () { - await openAndTestReportBreakage(TRACKING_PAGE, "trackingprotection"); - }); - - Services.prefs.clearUserPref(TP_PREF); -}); - -add_task(async function testCR() { - Services.prefs.setIntPref( - CB_PREF, - Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER - ); - // Make sure that we correctly strip the query. - let url = COOKIE_PAGE + "?a=b&1=abc&unicode=🦊"; - await BrowserTestUtils.withNewTab(url, async function () { - await openAndTestReportBreakage(COOKIE_PAGE, "cookierestrictions"); - }); - - Services.prefs.clearUserPref(CB_PREF); -}); - -add_task(async function testFP() { - Services.prefs.setIntPref(CB_PREF, Ci.nsICookieService.BEHAVIOR_ACCEPT); - Services.prefs.setBoolPref(FP_PREF, true); - // Make sure that we correctly strip the query. - let url = TRACKING_PAGE + "?a=b&1=abc&unicode=🦊"; - await BrowserTestUtils.withNewTab(url, async function (browser) { - let promise = waitForContentBlockingEvent(); - await SpecialPowers.spawn(browser, [], function () { - content.postMessage("fingerprinting", "*"); - }); - await promise; - - await openAndTestReportBreakage(TRACKING_PAGE, "fingerprinting", true); - }); - - Services.prefs.clearUserPref(FP_PREF); - Services.prefs.clearUserPref(CB_PREF); -}); - -add_task(async function testCM() { - Services.prefs.setIntPref(CB_PREF, Ci.nsICookieService.BEHAVIOR_ACCEPT); - Services.prefs.setBoolPref(CM_PREF, true); - // Make sure that we correctly strip the query. - let url = TRACKING_PAGE + "?a=b&1=abc&unicode=🦊"; - await BrowserTestUtils.withNewTab(url, async function (browser) { - let promise = waitForContentBlockingEvent(); - await SpecialPowers.spawn(browser, [], function () { - content.postMessage("cryptomining", "*"); - }); - await promise; - - await openAndTestReportBreakage(TRACKING_PAGE, "cryptomining", true); - }); - - Services.prefs.clearUserPref(CM_PREF); - Services.prefs.clearUserPref(CB_PREF); -}); - -async function openAndTestReportBreakage(url, tags, error = false) { - await openProtectionsPanel(); - - let siteNotWorkingButton = document.getElementById( - "protections-popup-tp-switch-breakage-link" - ); - ok( - BrowserTestUtils.isVisible(siteNotWorkingButton), - "site not working button is visible" - ); - let siteNotWorkingView = document.getElementById( - "protections-popup-siteNotWorkingView" - ); - let viewShown = BrowserTestUtils.waitForEvent( - siteNotWorkingView, - "ViewShown" - ); - siteNotWorkingButton.click(); - await viewShown; - - let sendReportButton = document.getElementById( - "protections-popup-siteNotWorkingView-sendReport" - ); - let sendReportView = document.getElementById( - "protections-popup-sendReportView" - ); - viewShown = BrowserTestUtils.waitForEvent(sendReportView, "ViewShown"); - sendReportButton.click(); - await viewShown; - - ok(true, "Report breakage view was shown"); - - await testReportBreakageSubmit(url, tags, error, false); -} - -// This function assumes that the breakage report view is ready. -async function testReportBreakageSubmit(url, tags, error, hasException) { - // Setup a mock server for receiving breakage reports. - let server = new HttpServer(); - server.start(-1); - let i = server.identity; - let path = - i.primaryScheme + "://" + i.primaryHost + ":" + i.primaryPort + "/"; - - Services.prefs.setStringPref(PREF_REPORT_BREAKAGE_URL, path); - - let comments = document.getElementById( - "protections-popup-sendReportView-collection-comments" - ); - is(comments.value, "", "Comments textarea should initially be empty"); - - let submitButton = document.getElementById( - "protections-popup-sendReportView-submit" - ); - let reportURL = document.getElementById( - "protections-popup-sendReportView-collection-url" - ).value; - - is(reportURL, url, "Shows the correct URL in the report UI."); - - // Make sure that sending the report closes the identity popup. - let popuphidden = BrowserTestUtils.waitForEvent( - gProtectionsHandler._protectionsPopup, - "popuphidden" - ); - - // Check that we're receiving a good report. - await new Promise(resolve => { - server.registerPathHandler("/", async (request, response) => { - is(request.method, "POST", "request was a post"); - - // Extract and "parse" the form data in the request body. - let body = CommonUtils.readBytesFromInputStream(request.bodyInputStream); - let boundary = request - .getHeader("Content-Type") - .match(/boundary=-+([^-]*)/i)[1]; - let regex = new RegExp("-+" + boundary + "-*\\s+"); - let sections = body.split(regex); - - let prefs = [ - "privacy.trackingprotection.enabled", - "privacy.trackingprotection.pbmode.enabled", - "urlclassifier.trackingTable", - "network.http.referer.defaultPolicy", - "network.http.referer.defaultPolicy.pbmode", - "network.cookie.cookieBehavior", - "privacy.annotate_channels.strict_list.enabled", - "privacy.restrict3rdpartystorage.expiration", - "privacy.trackingprotection.fingerprinting.enabled", - "privacy.trackingprotection.cryptomining.enabled", - "privacy.globalprivacycontrol.enabled", - ]; - let prefsBody = ""; - - for (let pref of prefs) { - prefsBody += `${pref}: ${Preferences.get(pref)}\r\n`; - } - - Assert.deepEqual( - sections, - [ - "", - `Content-Disposition: form-data; name=\"title\"\r\n\r\n${ - Services.io.newURI(reportURL).host - }\r\n`, - 'Content-Disposition: form-data; name="body"\r\n\r\n' + - `Full URL: ${reportURL + "?"}\r\n` + - `userAgent: ${navigator.userAgent}\r\n\r\n` + - "**Preferences**\r\n" + - `${prefsBody}\r\n` + - `hasException: ${hasException}\r\n\r\n` + - "**Comments**\r\n" + - "This is a comment\r\n", - 'Content-Disposition: form-data; name="labels"\r\n\r\n' + - `${hasException ? "" : tags}\r\n`, - "", - ], - "Should send the correct form data" - ); - - if (error) { - response.setStatusLine(request.httpVersion, 500, "Request failed"); - } else { - response.setStatusLine(request.httpVersion, 201, "Entry created"); - } - - resolve(); - }); - - comments.value = "This is a comment"; - submitButton.click(); - }); - - let errorMessage = document.getElementById( - "protections-popup-sendReportView-report-error" - ); - if (error) { - await TestUtils.waitForCondition(() => - BrowserTestUtils.isVisible(errorMessage) - ); - is( - comments.value, - "This is a comment", - "Comment not cleared in case of an error" - ); - gProtectionsHandler._protectionsPopup.hidePopup(); - } else { - ok(BrowserTestUtils.isHidden(errorMessage), "Error message not shown"); - } - - await popuphidden; - - // Stop the server. - await new Promise(r => server.stop(r)); - - Services.prefs.clearUserPref(PREF_REPORT_BREAKAGE_URL); -} diff --git a/browser/base/content/test/sanitize/browser.toml b/browser/base/content/test/sanitize/browser.toml index 814dc54c3d..3c53723833 100644 --- a/browser/base/content/test/sanitize/browser.toml +++ b/browser/base/content/test/sanitize/browser.toml @@ -36,4 +36,6 @@ support-files = [ ["browser_sanitizeDialog_v2.js"] +["browser_sanitizeDialog_v2_dataSizes.js"] + ["browser_sanitizeOnShutdown_migration.js"] diff --git a/browser/base/content/test/sanitize/browser_sanitize-timespans.js b/browser/base/content/test/sanitize/browser_sanitize-timespans.js index 30ccb90666..f9be12775b 100644 --- a/browser/base/content/test/sanitize/browser_sanitize-timespans.js +++ b/browser/base/content/test/sanitize/browser_sanitize-timespans.js @@ -8,9 +8,6 @@ const { PlacesTestUtils } = ChromeUtils.importESModule( var now_mSec = Date.now(); var now_uSec = now_mSec * 1000; -const kMsecPerMin = 60 * 1000; -const kUsecPerMin = 60 * 1000000; - function promiseFormHistoryRemoved() { return new Promise(resolve => { Services.obs.addObserver(function onfh() { diff --git a/browser/base/content/test/sanitize/browser_sanitizeDialog.js b/browser/base/content/test/sanitize/browser_sanitizeDialog.js index 2df7d83c6e..a1e8a5dc85 100644 --- a/browser/base/content/test/sanitize/browser_sanitizeDialog.js +++ b/browser/base/content/test/sanitize/browser_sanitizeDialog.js @@ -22,9 +22,6 @@ ChromeUtils.defineESModuleGetters(this, { Timer: "resource://gre/modules/Timer.sys.mjs", }); -const kMsecPerMin = 60 * 1000; -const kUsecPerMin = 60 * 1000000; - /** * Ensures that the specified URIs are either cleared or not. * @@ -694,10 +691,6 @@ DialogHelper.prototype = { }, }; -function promiseSanitizationComplete() { - return TestUtils.topicObserved("sanitizer-sanitization-complete"); -} - /** * Adds a download to history. * @@ -752,21 +745,6 @@ async function formNameExists(name) { } /** - * Removes all history visits, downloads, and form entries. - */ -async function blankSlate() { - let publicList = await Downloads.getList(Downloads.PUBLIC); - let downloads = await publicList.getAll(); - for (let download of downloads) { - await publicList.remove(download); - await download.finalize(true); - } - - await FormHistory.update({ op: "remove" }); - await PlacesUtils.history.clear(); -} - -/** * Ensures that the given pref is the expected value. * * @param aPrefName diff --git a/browser/base/content/test/sanitize/browser_sanitizeDialog_v2.js b/browser/base/content/test/sanitize/browser_sanitizeDialog_v2.js index 29f760f57f..8ae0263c82 100644 --- a/browser/base/content/test/sanitize/browser_sanitizeDialog_v2.js +++ b/browser/base/content/test/sanitize/browser_sanitizeDialog_v2.js @@ -20,33 +20,9 @@ ChromeUtils.defineESModuleGetters(this, { PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs", Timer: "resource://gre/modules/Timer.sys.mjs", PermissionTestUtils: "resource://testing-common/PermissionTestUtils.sys.mjs", - FileTestUtils: "resource://testing-common/FileTestUtils.sys.mjs", Downloads: "resource://gre/modules/Downloads.sys.mjs", }); -const kMsecPerMin = 60 * 1000; -const kUsecPerMin = 60 * 1000000; -let today = Date.now() - new Date().setHours(0, 0, 0, 0); -let nowMSec = Date.now(); -let nowUSec = nowMSec * 1000; -let fileURL; - -const TEST_TARGET_FILE_NAME = "test-download.txt"; -const TEST_QUOTA_USAGE_HOST = "example.com"; -const TEST_QUOTA_USAGE_ORIGIN = "https://" + TEST_QUOTA_USAGE_HOST; -const TEST_QUOTA_USAGE_URL = - getRootDirectory(gTestPath).replace( - "chrome://mochitests/content", - TEST_QUOTA_USAGE_ORIGIN - ) + "site_data_test.html"; - -const siteOrigins = [ - "https://www.example.com", - "https://example.org", - "http://localhost:8000", - "http://localhost:3000", -]; - /** * Ensures that the specified URIs are either cleared or not. * @@ -167,90 +143,6 @@ async function addDownloadWithMinutesAgo(aExpectedPathList, aMinutesAgo) { aExpectedPathList.push(name); } -/** - * Adds multiple downloads to the PUBLIC download list - */ -async function addToDownloadList() { - const url = createFileURL(); - const downloadsList = await Downloads.getList(Downloads.PUBLIC); - let timeOptions = [1, 2, 4, 24, 128, 128]; - let buffer = 100000; - - for (let i = 0; i < timeOptions.length; i++) { - let timeDownloaded = 60 * kMsecPerMin * timeOptions[i]; - if (timeOptions[i] === 24) { - timeDownloaded = today; - } - - let download = await Downloads.createDownload({ - source: { url: url.spec, isPrivate: false }, - target: { path: FileTestUtils.getTempFile(TEST_TARGET_FILE_NAME).path }, - startTime: { - getTime: _ => { - return nowMSec - timeDownloaded + buffer; - }, - }, - }); - - Assert.ok(!!download); - downloadsList.add(download); - } - let items = await downloadsList.getAll(); - Assert.equal(items.length, 6, "Items were added to the list"); -} - -async function addToSiteUsage() { - // Fill indexedDB with test data. - // Don't wait for the page to load, to register the content event handler as quickly as possible. - // If this test goes intermittent, we might have to tell the page to wait longer before - // firing the event. - BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_QUOTA_USAGE_URL, false); - await BrowserTestUtils.waitForContentEvent( - gBrowser.selectedBrowser, - "test-indexedDB-done", - false, - null, - true - ); - BrowserTestUtils.removeTab(gBrowser.selectedTab); - - let siteLastAccessed = [1, 2, 4, 24]; - - let staticUsage = 4096 * 6; - // Add a time buffer so the site access falls within the time range - const buffer = 10000; - - // Change lastAccessed of sites - for (let index = 0; index < siteLastAccessed.length; index++) { - let lastAccessedTime = 60 * kMsecPerMin * siteLastAccessed[index]; - if (siteLastAccessed[index] === 24) { - lastAccessedTime = today; - } - - let site = SiteDataManager._testInsertSite(siteOrigins[index], { - quotaUsage: staticUsage, - lastAccessed: (nowMSec - lastAccessedTime + buffer) * 1000, - }); - Assert.ok(site, "Site added successfully"); - } -} - -/** - * Helper function to create file URL to open - * - * @returns {Object} a file URL - */ -function createFileURL() { - if (!fileURL) { - let file = Services.dirsvc.get("TmpD", Ci.nsIFile); - file.append("foo.txt"); - file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); - - fileURL = Services.io.newFileURI(file); - } - return fileURL; -} - add_setup(async function () { requestLongerTimeout(3); await blankSlate(); @@ -268,248 +160,6 @@ add_setup(async function () { }); /** - * Removes all history visits, downloads, and form entries. - */ -async function blankSlate() { - let publicList = await Downloads.getList(Downloads.PUBLIC); - let downloads = await publicList.getAll(); - for (let download of downloads) { - await publicList.remove(download); - await download.finalize(true); - } - - await FormHistory.update({ op: "remove" }); - await PlacesUtils.history.clear(); -} - -/** - * This wraps the dialog and provides some convenience methods for interacting - * with it. - * - * @param browserWin (optional) - * The browser window that the dialog is expected to open in. If not - * supplied, the initial browser window of the test run is used. - * @param mode (optional) - * One of - * clear on shutdown settings context ("clearOnShutdown"), - * clear site data settings context ("clearSiteData"), - * clear history context ("clearHistory"), - * browser context ("browser") - * "browser" by default - */ -function DialogHelper(openContext = "browser") { - this._browserWin = window; - this.win = null; - this._mode = openContext; - this.promiseClosed = new Promise(resolve => { - this._resolveClosed = resolve; - }); -} - -DialogHelper.prototype = { - /** - * "Presses" the dialog's OK button. - */ - acceptDialog() { - let dialogEl = this.win.document.querySelector("dialog"); - is( - dialogEl.getButton("accept").disabled, - false, - "Dialog's OK button should not be disabled" - ); - dialogEl.acceptDialog(); - }, - - /** - * "Presses" the dialog's Cancel button. - */ - cancelDialog() { - this.win.document.querySelector("dialog").cancelDialog(); - }, - - /** - * (Un)checks a history scope checkbox (browser & download history, - * form history, etc.). - * - * @param aPrefName - * The final portion of the checkbox's privacy.cpd.* preference name - * @param aCheckState - * True if the checkbox should be checked, false otherwise - */ - checkPrefCheckbox(aPrefName, aCheckState) { - var cb = this.win.document.querySelectorAll( - "checkbox[id='" + aPrefName + "']" - ); - is(cb.length, 1, "found checkbox for " + aPrefName + " id"); - if (cb[0].checked != aCheckState) { - cb[0].click(); - } - }, - - /** - * @param {String} aCheckboxId - * The checkbox id name - * @param {Boolean} aCheckState - * True if the checkbox should be checked, false otherwise - */ - validateCheckbox(aCheckboxId, aCheckState) { - let cb = this.win.document.querySelectorAll( - "checkbox[id='" + aCheckboxId + "']" - ); - is(cb.length, 1, `found checkbox for id=${aCheckboxId}`); - is( - cb[0].checked, - aCheckState, - `checkbox for ${aCheckboxId} is ${aCheckState}` - ); - }, - - /** - * Makes sure all the checkboxes are checked. - */ - _checkAllCheckboxesCustom(check) { - var cb = this.win.document.querySelectorAll(".clearingItemCheckbox"); - ok(cb.length, "found checkboxes for ids"); - for (var i = 0; i < cb.length; ++i) { - if (cb[i].checked != check) { - cb[i].click(); - } - } - }, - - checkAllCheckboxes() { - this._checkAllCheckboxesCustom(true); - }, - - uncheckAllCheckboxes() { - this._checkAllCheckboxesCustom(false); - }, - - /** - * @return The dialog's duration dropdown - */ - getDurationDropdown() { - return this.win.document.getElementById("sanitizeDurationChoice"); - }, - - /** - * @return The clear-everything warning box - */ - getWarningPanel() { - return this.win.document.getElementById("sanitizeEverythingWarningBox"); - }, - - /** - * @return True if the "Everything" warning panel is visible (as opposed to - * the tree) - */ - isWarningPanelVisible() { - return !this.getWarningPanel().hidden; - }, - - /** - * Opens the clear recent history dialog. Before calling this, set - * this.onload to a function to execute onload. It should close the dialog - * when done so that the tests may continue. Set this.onunload to a function - * to execute onunload. this.onunload is optional. If it returns true, the - * caller is expected to call promiseAsyncUpdates at some point; if false is - * returned, promiseAsyncUpdates is called automatically. - */ - async open() { - let dialogPromise = BrowserTestUtils.promiseAlertDialogOpen( - null, - "chrome://browser/content/sanitize_v2.xhtml", - { - isSubDialog: true, - } - ); - - // We want to simulate opening the dialog inside preferences for clear history - // and clear site data - if (this._mode != "browser") { - await openPreferencesViaOpenPreferencesAPI("privacy", { - leaveOpen: true, - }); - let tabWindow = gBrowser.selectedBrowser.contentWindow; - let clearDialogOpenButtonId = this._mode + "Button"; - // the id for clear on shutdown is of a different format - if (this._mode == "clearOnShutdown") { - // set always clear to true to enable the clear on shutdown dialog - let enableSettingsCheckbox = - tabWindow.document.getElementById("alwaysClear"); - if (!enableSettingsCheckbox.checked) { - enableSettingsCheckbox.click(); - } - clearDialogOpenButtonId = "clearDataSettings"; - } - // open dialog - tabWindow.document.getElementById(clearDialogOpenButtonId).click(); - } - // We open the dialog in the chrome context in other cases - else { - executeSoon(() => { - Sanitizer.showUI(this._browserWin, this._mode); - }); - } - - this.win = await dialogPromise; - this.win.addEventListener( - "load", - () => { - // Run onload on next tick so that gSanitizePromptDialog.init can run first. - executeSoon(async () => { - await this.win.gSanitizePromptDialog.dataSizesFinishedUpdatingPromise; - this.onload(); - }); - }, - { once: true } - ); - this.win.addEventListener( - "unload", - () => { - // Some exceptions that reach here don't reach the test harness, but - // ok()/is() do... - (async () => { - if (this.onunload) { - await this.onunload(); - } - if (this._mode != "browser") { - BrowserTestUtils.removeTab(gBrowser.selectedTab); - } - await PlacesTestUtils.promiseAsyncUpdates(); - this._resolveClosed(); - this.win = null; - })(); - }, - { once: true } - ); - }, - - /** - * Selects a duration in the duration dropdown. - * - * @param aDurVal - * One of the Sanitizer.TIMESPAN_* values - */ - selectDuration(aDurVal) { - this.getDurationDropdown().value = aDurVal; - if (aDurVal === Sanitizer.TIMESPAN_EVERYTHING) { - is( - this.isWarningPanelVisible(), - true, - "Warning panel should be visible for TIMESPAN_EVERYTHING" - ); - } else { - is( - this.isWarningPanelVisible(), - false, - "Warning panel should not be visible for non-TIMESPAN_EVERYTHING" - ); - } - }, -}; - -/** * Ensures that the given pref is the expected value. * * @param aPrefName @@ -533,58 +183,6 @@ function visitTimeForMinutesAgo(aMinutesAgo) { return nowUSec - aMinutesAgo * kUsecPerMin; } -function promiseSanitizationComplete() { - return TestUtils.topicObserved("sanitizer-sanitization-complete"); -} - -/** - * Helper function to validate the data sizes shown for each time selection - * - * @param {DialogHelper} dh - dialog object to access window and timespan - */ -async function validateDataSizes(dialogHelper) { - let timespans = [ - "TIMESPAN_HOUR", - "TIMESPAN_2HOURS", - "TIMESPAN_4HOURS", - "TIMESPAN_TODAY", - "TIMESPAN_EVERYTHING", - ]; - - // get current data sizes from siteDataManager - let cacheUsage = await SiteDataManager.getCacheSize(); - let quotaUsage = await SiteDataManager.getQuotaUsageForTimeRanges(timespans); - - for (let i = 0; i < timespans.length; i++) { - // select timespan to check - dialogHelper.selectDuration(Sanitizer[timespans[i]]); - - // get the elements - let clearCookiesAndSiteDataCheckbox = - dialogHelper.win.document.getElementById("cookiesAndStorage"); - let clearCacheCheckbox = dialogHelper.win.document.getElementById("cache"); - - let [convertedQuotaUsage] = DownloadUtils.convertByteUnits( - quotaUsage[timespans[i]] - ); - let [, convertedCacheUnit] = DownloadUtils.convertByteUnits(cacheUsage); - - // Ensure l10n is finished before inspecting the category labels. - await dialogHelper.win.document.l10n.translateElements([ - clearCookiesAndSiteDataCheckbox, - clearCacheCheckbox, - ]); - ok( - clearCacheCheckbox.label.includes(convertedCacheUnit), - "Should show the cache usage" - ); - ok( - clearCookiesAndSiteDataCheckbox.label.includes(convertedQuotaUsage), - `Should show the quota usage as ${convertedQuotaUsage}` - ); - } -} - /** * * Opens dialog in the provided context and selects the checkboxes @@ -602,7 +200,7 @@ async function performActionsOnDialog({ cache = false, siteSettings = false, }) { - let dh = new DialogHelper(context); + let dh = new ClearHistoryDialogHelper({ mode: context }); dh.onload = function () { this.selectDuration(timespan); this.checkPrefCheckbox( @@ -622,7 +220,7 @@ async function performActionsOnDialog({ * Initializes the dialog to its default state. */ add_task(async function default_state() { - let dh = new DialogHelper(); + let dh = new ClearHistoryDialogHelper(); dh.onload = function () { // Select "Last Hour" this.selectDuration(Sanitizer.TIMESPAN_HOUR); @@ -647,7 +245,7 @@ add_task(async function test_cancel() { } await PlacesTestUtils.addVisits(places); - let dh = new DialogHelper(); + let dh = new ClearHistoryDialogHelper(); dh.onload = function () { this.selectDuration(Sanitizer.TIMESPAN_HOUR); this.checkPrefCheckbox("historyFormDataAndDownloads", false); @@ -662,6 +260,72 @@ add_task(async function test_cancel() { await dh.promiseClosed; }); +// test remembering user options for various entry points +add_task(async function test_pref_remembering() { + let dh = new ClearHistoryDialogHelper({ mode: "clearSiteData" }); + dh.onload = function () { + this.checkPrefCheckbox("cookiesAndStorage", false); + this.checkPrefCheckbox("siteSettings", true); + + this.acceptDialog(); + }; + dh.open(); + await dh.promiseClosed; + + // validate if prefs are remembered + dh = new ClearHistoryDialogHelper({ mode: "clearSiteData" }); + dh.onload = function () { + this.validateCheckbox("cookiesAndStorage", false); + this.validateCheckbox("siteSettings", true); + + this.checkPrefCheckbox("cookiesAndStorage", true); + this.checkPrefCheckbox("siteSettings", false); + + // we will test cancelling the dialog, to make sure it doesn't remember + // the prefs when cancelled + this.cancelDialog(); + }; + dh.open(); + await dh.promiseClosed; + + // validate if prefs did not change since we cancelled the dialog + dh = new ClearHistoryDialogHelper({ mode: "clearSiteData" }); + dh.onload = function () { + this.validateCheckbox("cookiesAndStorage", false); + this.validateCheckbox("siteSettings", true); + + this.cancelDialog(); + }; + dh.open(); + await dh.promiseClosed; + + // test rememebering prefs from the clear history context + // since clear history and clear site data have seperate remembering + // of prefs + dh = new ClearHistoryDialogHelper({ mode: "clearHistory" }); + dh.onload = function () { + this.checkPrefCheckbox("cookiesAndStorage", true); + this.checkPrefCheckbox("siteSettings", false); + this.checkPrefCheckbox("cache", false); + + this.acceptDialog(); + }; + dh.open(); + await dh.promiseClosed; + + // validate if prefs are remembered across both clear history and browser + dh = new ClearHistoryDialogHelper({ mode: "browser" }); + dh.onload = function () { + this.validateCheckbox("cookiesAndStorage", true); + this.validateCheckbox("siteSettings", false); + this.validateCheckbox("cache", false); + + this.cancelDialog(); + }; + dh.open(); + await dh.promiseClosed; +}); + /** * Ensures that the "Everything" duration option works. */ @@ -681,7 +345,7 @@ add_task(async function test_everything() { let promiseSanitized = promiseSanitizationComplete(); await PlacesTestUtils.addVisits(places); - let dh = new DialogHelper(); + let dh = new ClearHistoryDialogHelper(); dh.onload = function () { is( this.isWarningPanelVisible(), @@ -728,7 +392,7 @@ add_task(async function test_everything_warning() { let promiseSanitized = promiseSanitizationComplete(); await PlacesTestUtils.addVisits(places); - let dh = new DialogHelper(); + let dh = new ClearHistoryDialogHelper(); dh.onload = function () { is( this.isWarningPanelVisible(), @@ -761,7 +425,7 @@ add_task(async function test_everything_warning() { * and enabled when at least one checkbox is checked */ add_task(async function testAcceptButtonDisabled() { - let dh = new DialogHelper(); + let dh = new ClearHistoryDialogHelper(); dh.onload = async function () { let clearButton = this.win.document .querySelector("dialog") @@ -769,12 +433,6 @@ add_task(async function testAcceptButtonDisabled() { this.uncheckAllCheckboxes(); await new Promise(resolve => SimpleTest.executeSoon(resolve)); is(clearButton.disabled, true, "Clear button should be disabled"); - // await BrowserTestUtils.waitForMutationCondition( - // clearButton, - // { attributes: true }, - // () => clearButton.disabled, - // "Clear button should be disabled" - // ); this.checkPrefCheckbox("cache", true); await new Promise(resolve => SimpleTest.executeSoon(resolve)); @@ -790,7 +448,7 @@ add_task(async function testAcceptButtonDisabled() { * Tests to see if the warning box is hidden when opened in the clear on shutdown context */ add_task(async function testWarningBoxInClearOnShutdown() { - let dh = new DialogHelper("clearSiteData"); + let dh = new ClearHistoryDialogHelper({ mode: "clearSiteData" }); dh.onload = function () { this.selectDuration(Sanitizer.TIMESPAN_EVERYTHING); is( @@ -803,7 +461,7 @@ add_task(async function testWarningBoxInClearOnShutdown() { dh.open(); await dh.promiseClosed; - dh = new DialogHelper("clearOnShutdown"); + dh = new ClearHistoryDialogHelper({ mode: "clearOnShutdown" }); dh.onload = function () { is( BrowserTestUtils.isVisible(this.getWarningPanel()), @@ -853,7 +511,7 @@ add_task(async function test_history_downloads_checked() { await PlacesTestUtils.addVisits(places); - let dh = new DialogHelper(); + let dh = new ClearHistoryDialogHelper(); dh.onload = function () { this.selectDuration(Sanitizer.TIMESPAN_HOUR); this.checkPrefCheckbox("historyFormDataAndDownloads", true); @@ -905,7 +563,7 @@ add_task(async function test_cannot_clear_history() { }); let uris = [pURI]; - let dh = new DialogHelper(); + let dh = new ClearHistoryDialogHelper(); dh.onload = function () { var cb = this.win.document.querySelectorAll( "checkbox[id='historyFormDataAndDownloads']" @@ -932,7 +590,7 @@ add_task(async function test_cannot_clear_history() { add_task(async function test_no_formdata_history_to_clear() { let promiseSanitized = promiseSanitizationComplete(); - let dh = new DialogHelper(); + let dh = new ClearHistoryDialogHelper(); dh.onload = function () { var cb = this.win.document.querySelectorAll( "checkbox[id='historyFormDataAndDownloads']" @@ -955,7 +613,7 @@ add_task(async function test_form_entries() { let promiseSanitized = promiseSanitizationComplete(); - let dh = new DialogHelper(); + let dh = new ClearHistoryDialogHelper(); dh.onload = function () { var cb = this.win.document.querySelectorAll( "checkbox[id='historyFormDataAndDownloads']" @@ -975,97 +633,13 @@ add_task(async function test_form_entries() { await dh.promiseClosed; }); -add_task(async function test_cookie_sizes() { - await clearAndValidateDataSizes({ - clearCookies: true, - clearCache: false, - clearDownloads: false, - timespan: Sanitizer.TIMESPAN_HOUR, - }); - await clearAndValidateDataSizes({ - clearCookies: true, - clearCache: false, - clearDownloads: false, - timespan: Sanitizer.TIMESPAN_4HOURS, - }); - await clearAndValidateDataSizes({ - clearCookies: true, - clearCache: false, - clearDownloads: false, - timespan: Sanitizer.TIMESPAN_EVERYTHING, - }); -}); - -add_task(async function test_cache_sizes() { - await clearAndValidateDataSizes({ - clearCookies: false, - clearCache: true, - clearDownloads: false, - timespan: Sanitizer.TIMESPAN_HOUR, - }); - await clearAndValidateDataSizes({ - clearCookies: false, - clearCache: true, - clearDownloads: false, - timespan: Sanitizer.TIMESPAN_4HOURS, - }); - await clearAndValidateDataSizes({ - clearCookies: false, - clearCache: true, - clearDownloads: false, - timespan: Sanitizer.TIMESPAN_EVERYTHING, - }); -}); - -add_task(async function test_downloads_sizes() { - await clearAndValidateDataSizes({ - clearCookies: false, - clearCache: false, - clearDownloads: true, - timespan: Sanitizer.TIMESPAN_HOUR, - }); - await clearAndValidateDataSizes({ - clearCookies: false, - clearCache: false, - clearDownloads: true, - timespan: Sanitizer.TIMESPAN_4HOURS, - }); - await clearAndValidateDataSizes({ - clearCookies: false, - clearCache: false, - clearDownloads: true, - timespan: Sanitizer.TIMESPAN_EVERYTHING, - }); -}); - -add_task(async function test_all_data_sizes() { - await clearAndValidateDataSizes({ - clearCookies: true, - clearCache: true, - clearDownloads: true, - timespan: Sanitizer.TIMESPAN_HOUR, - }); - await clearAndValidateDataSizes({ - clearCookies: true, - clearCache: true, - clearDownloads: true, - timespan: Sanitizer.TIMESPAN_4HOURS, - }); - await clearAndValidateDataSizes({ - clearCookies: true, - clearCache: true, - clearDownloads: true, - timespan: Sanitizer.TIMESPAN_EVERYTHING, - }); -}); - // test the case when we open the dialog through the clear on shutdown settings add_task(async function test_clear_on_shutdown() { await SpecialPowers.pushPrefEnv({ set: [["privacy.sanitize.sanitizeOnShutdown", true]], }); - let dh = new DialogHelper("clearOnShutdown"); + let dh = new ClearHistoryDialogHelper({ mode: "clearOnShutdown" }); dh.onload = async function () { this.uncheckAllCheckboxes(); this.checkPrefCheckbox("historyFormDataAndDownloads", false); @@ -1134,7 +708,7 @@ add_task(async function test_clear_on_shutdown() { await ensureDownloadsClearedState(downloadIDs, false); await ensureDownloadsClearedState(olderDownloadIDs, false); - dh = new DialogHelper("clearOnShutdown"); + dh = new ClearHistoryDialogHelper({ mode: "clearOnShutdown" }); dh.onload = async function () { this.uncheckAllCheckboxes(); this.checkPrefCheckbox("historyFormDataAndDownloads", true); @@ -1192,89 +766,6 @@ add_task(async function test_clear_on_shutdown() { await SiteDataTestUtils.clear(); }); -// test default prefs for entry points -add_task(async function test_defaults_prefs() { - let dh = new DialogHelper("clearSiteData"); - dh.onload = function () { - this.validateCheckbox("historyFormDataAndDownloads", false); - this.validateCheckbox("cache", true); - this.validateCheckbox("cookiesAndStorage", true); - this.validateCheckbox("siteSettings", false); - - this.cancelDialog(); - }; - dh.open(); - await dh.promiseClosed; - - // We don't need to specify the mode again, - // as the default mode is taken (browser, clear history) - - dh = new DialogHelper(); - dh.onload = function () { - // Default checked for browser and clear history mode - this.validateCheckbox("historyFormDataAndDownloads", true); - this.validateCheckbox("cache", true); - this.validateCheckbox("cookiesAndStorage", true); - this.validateCheckbox("siteSettings", false); - - this.cancelDialog(); - }; - dh.open(); - await dh.promiseClosed; -}); - -/** - * Helper function to simulate switching timespan selections and - * validate data sizes before and after clearing - * - * @param {Object} - * clearCookies - boolean - * clearDownloads - boolean - * clearCaches - boolean - * timespan - one of Sanitizer.TIMESPAN_* - */ -async function clearAndValidateDataSizes({ - clearCache, - clearDownloads, - clearCookies, - timespan, -}) { - await blankSlate(); - - await addToDownloadList(); - await addToSiteUsage(); - let promiseSanitized = promiseSanitizationComplete(); - - await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); - - let dh = new DialogHelper(); - dh.onload = async function () { - await validateDataSizes(this); - this.checkPrefCheckbox("cache", clearCache); - this.checkPrefCheckbox("cookiesAndStorage", clearCookies); - this.checkPrefCheckbox("historyFormDataAndDownloads", clearDownloads); - this.selectDuration(timespan); - this.acceptDialog(); - }; - dh.onunload = async function () { - await promiseSanitized; - }; - dh.open(); - await dh.promiseClosed; - - let dh2 = new DialogHelper(); - // Check if the newly cleared values are reflected - dh2.onload = async function () { - await validateDataSizes(this); - this.acceptDialog(); - }; - dh2.open(); - await dh2.promiseClosed; - - await SiteDataTestUtils.clear(); - BrowserTestUtils.removeTab(gBrowser.selectedTab); -} - add_task(async function testEntryPointTelemetry() { Services.fog.testResetFOG(); @@ -1401,27 +892,47 @@ add_task(async function testClearingOptionsTelemetry() { ); }); -add_task(async function testCheckboxStatesAfterMigration() { +add_task(async function testClearHistoryCheckboxStatesAfterMigration() { await SpecialPowers.pushPrefEnv({ set: [ - ["privacy.clearOnShutdown.history", false], - ["privacy.clearOnShutdown.formdata", true], - ["privacy.clearOnShutdown.cookies", true], - ["privacy.clearOnShutdown.offlineApps", false], - ["privacy.clearOnShutdown.sessions", false], - ["privacy.clearOnShutdown.siteSettings", false], - ["privacy.clearOnShutdown.cache", true], - ["privacy.clearOnShutdown_v2.cookiesAndStorage", false], - ["privacy.sanitize.sanitizeOnShutdown.hasMigratedToNewPrefs", false], + ["privacy.cpd.history", false], + ["privacy.cpd.formdata", true], + ["privacy.cpd.cookies", true], + ["privacy.cpd.offlineApps", false], + ["privacy.cpd.sessions", false], + ["privacy.cpd.siteSettings", false], + ["privacy.cpd.cache", true], + // Set cookiesAndStorage to verify that the pref is flipped in the test + ["privacy.clearHistory.cookiesAndStorage", false], + ["privacy.sanitize.cpd.hasMigratedToNewPrefs", false], ], }); - let dh = new DialogHelper("clearOnShutdown"); + let dh = new ClearHistoryDialogHelper({ mode: "clearHistory" }); dh.onload = function () { this.validateCheckbox("cookiesAndStorage", true); this.validateCheckbox("historyFormDataAndDownloads", false); this.validateCheckbox("cache", true); this.validateCheckbox("siteSettings", false); + + this.checkPrefCheckbox("siteSettings", true); + this.checkPrefCheckbox("cookiesAndStorage", false); + this.acceptDialog(); + }; + dh.open(); + await dh.promiseClosed; + + is( + Services.prefs.getBoolPref("privacy.sanitize.cpd.hasMigratedToNewPrefs"), + true, + "Migration is complete for cpd branch" + ); + + // make sure the migration doesn't run again + dh = new ClearHistoryDialogHelper({ mode: "clearHistory" }); + dh.onload = function () { + this.validateCheckbox("siteSettings", true); + this.validateCheckbox("cookiesAndStorage", false); this.cancelDialog(); }; dh.open(); diff --git a/browser/base/content/test/sanitize/browser_sanitizeDialog_v2_dataSizes.js b/browser/base/content/test/sanitize/browser_sanitizeDialog_v2_dataSizes.js new file mode 100644 index 0000000000..ccb3c7d519 --- /dev/null +++ b/browser/base/content/test/sanitize/browser_sanitizeDialog_v2_dataSizes.js @@ -0,0 +1,310 @@ +/* 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/. */ + +/** + * This tests the new clear history dialog's data size display functionality + */ +ChromeUtils.defineESModuleGetters(this, { + sinon: "resource://testing-common/Sinon.sys.mjs", + Sanitizer: "resource:///modules/Sanitizer.sys.mjs", +}); + +add_setup(async function () { + await blankSlate(); + registerCleanupFunction(async function () { + await blankSlate(); + await PlacesTestUtils.promiseAsyncUpdates(); + }); + await SpecialPowers.pushPrefEnv({ + set: [["privacy.sanitize.useOldClearHistoryDialog", false]], + }); +}); + +/** + * Helper function to validate the data sizes shown for each time selection + * + * @param {ClearHistoryDialogHelper} dh - dialog object to access window and timespan + */ +async function validateDataSizes(ClearHistoryDialogHelper) { + let timespans = [ + "TIMESPAN_HOUR", + "TIMESPAN_2HOURS", + "TIMESPAN_4HOURS", + "TIMESPAN_TODAY", + "TIMESPAN_EVERYTHING", + ]; + + // get current data sizes from siteDataManager + let cacheUsage = await SiteDataManager.getCacheSize(); + let quotaUsage = await SiteDataManager.getQuotaUsageForTimeRanges(timespans); + + for (let i = 0; i < timespans.length; i++) { + // select timespan to check + ClearHistoryDialogHelper.selectDuration(Sanitizer[timespans[i]]); + + // get the elements + let clearCookiesAndSiteDataCheckbox = + ClearHistoryDialogHelper.win.document.getElementById("cookiesAndStorage"); + let clearCacheCheckbox = + ClearHistoryDialogHelper.win.document.getElementById("cache"); + + let [convertedQuotaUsage] = DownloadUtils.convertByteUnits( + quotaUsage[timespans[i]] + ); + let [, convertedCacheUnit] = DownloadUtils.convertByteUnits(cacheUsage); + + // Ensure l10n is finished before inspecting the category labels. + await ClearHistoryDialogHelper.win.document.l10n.translateElements([ + clearCookiesAndSiteDataCheckbox, + clearCacheCheckbox, + ]); + ok( + clearCacheCheckbox.label.includes(convertedCacheUnit), + "Should show the cache usage" + ); + ok( + clearCookiesAndSiteDataCheckbox.label.includes(convertedQuotaUsage), + `Should show the quota usage as ${convertedQuotaUsage}` + ); + } +} + +/** + * Helper function to simulate switching timespan selections and + * validate data sizes before and after clearing + * + * @param {Object} + * clearCookies - boolean + * clearDownloads - boolean + * clearCaches - boolean + * timespan - one of Sanitizer.TIMESPAN_* + */ +async function clearAndValidateDataSizes({ + clearCache, + clearDownloads, + clearCookies, + timespan, +}) { + await blankSlate(); + + await addToSiteUsage(); + let promiseSanitized = promiseSanitizationComplete(); + + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + + let dh = new ClearHistoryDialogHelper({ checkingDataSizes: true }); + dh.onload = async function () { + await validateDataSizes(this); + this.checkPrefCheckbox("cache", clearCache); + this.checkPrefCheckbox("cookiesAndStorage", clearCookies); + this.checkPrefCheckbox("historyFormDataAndDownloads", clearDownloads); + this.selectDuration(timespan); + this.acceptDialog(); + }; + dh.onunload = async function () { + await promiseSanitized; + }; + dh.open(); + await dh.promiseClosed; + + let dh2 = new ClearHistoryDialogHelper({ checkingDataSizes: true }); + // Check if the newly cleared values are reflected + dh2.onload = async function () { + await validateDataSizes(this); + this.acceptDialog(); + }; + dh2.open(); + await dh2.promiseClosed; + + await SiteDataTestUtils.clear(); + BrowserTestUtils.removeTab(gBrowser.selectedTab); +} + +add_task(async function test_cookie_sizes() { + await clearAndValidateDataSizes({ + clearCookies: true, + clearCache: false, + clearDownloads: false, + timespan: Sanitizer.TIMESPAN_HOUR, + }); + await clearAndValidateDataSizes({ + clearCookies: true, + clearCache: false, + clearDownloads: false, + timespan: Sanitizer.TIMESPAN_4HOURS, + }); + await clearAndValidateDataSizes({ + clearCookies: true, + clearCache: false, + clearDownloads: false, + timespan: Sanitizer.TIMESPAN_EVERYTHING, + }); +}); + +add_task(async function test_cache_sizes() { + await clearAndValidateDataSizes({ + clearCookies: false, + clearCache: true, + clearDownloads: false, + timespan: Sanitizer.TIMESPAN_HOUR, + }); + await clearAndValidateDataSizes({ + clearCookies: false, + clearCache: true, + clearDownloads: false, + timespan: Sanitizer.TIMESPAN_4HOURS, + }); + await clearAndValidateDataSizes({ + clearCookies: false, + clearCache: true, + clearDownloads: false, + timespan: Sanitizer.TIMESPAN_EVERYTHING, + }); +}); + +add_task(async function test_all_data_sizes() { + await clearAndValidateDataSizes({ + clearCookies: true, + clearCache: true, + clearDownloads: true, + timespan: Sanitizer.TIMESPAN_HOUR, + }); + await clearAndValidateDataSizes({ + clearCookies: true, + clearCache: true, + clearDownloads: true, + timespan: Sanitizer.TIMESPAN_4HOURS, + }); + await clearAndValidateDataSizes({ + clearCookies: true, + clearCache: true, + clearDownloads: true, + timespan: Sanitizer.TIMESPAN_EVERYTHING, + }); +}); + +// This test makes sure that the user can change their timerange option +// even if the data sizes are not loaded yet. +add_task(async function testUIWithDataSizesLoading() { + await blankSlate(); + await addToSiteUsage(); + + let origGetQuotaUsageForTimeRanges = + SiteDataManager.getQuotaUsageForTimeRanges.bind(SiteDataManager); + let resolveStubFn; + let resolverAssigned = false; + + let dh = new ClearHistoryDialogHelper(); + // Create a sandbox for isolated stubbing within the test + let sandbox = sinon.createSandbox(); + sandbox + .stub(SiteDataManager, "getQuotaUsageForTimeRanges") + .callsFake(async (...args) => { + info("stub called"); + + let dataSizesReadyToLoadPromise = new Promise(resolve => { + resolveStubFn = resolve; + info("Sending message to notify dialog that the resolver is assigned"); + window.postMessage("resolver-assigned", "*"); + resolverAssigned = true; + }); + await dataSizesReadyToLoadPromise; + return origGetQuotaUsageForTimeRanges(...args); + }); + dh.onload = async function () { + // we add this event listener in the case where init finishes before the resolver is assigned + if (!resolverAssigned) { + await new Promise(resolve => { + let listener = event => { + if (event.data === "resolver-assigned") { + window.removeEventListener("message", listener); + // we are ready to test the dialog without any data sizes loaded + resolve(); + } + }; + window.addEventListener("message", listener); + }); + } + + ok( + !this.win.gSanitizePromptDialog._dataSizesUpdated, + "Data sizes should not have loaded yet" + ); + this.selectDuration(Sanitizer.TIMESPAN_2HOURS); + + info("triggering loading state end"); + resolveStubFn(); + + await this.win.gSanitizePromptDialog.dataSizesFinishedUpdatingPromise; + + validateDataSizes(this); + this.cancelDialog(); + }; + dh.open(); + await dh.promiseClosed; + + // Restore the sandbox after the test is complete + sandbox.restore(); +}); + +add_task(async function testClearingBeforeDataSizesLoad() { + await blankSlate(); + await addToSiteUsage(); + + // add site data that we can verify if it gets cleared + await createDummyDataForHost("example.org"); + await createDummyDataForHost("example.com"); + + ok( + await SiteDataTestUtils.hasIndexedDB("https://example.org"), + "We have indexedDB data for example.org" + ); + ok( + await SiteDataTestUtils.hasIndexedDB("https://example.com"), + "We have indexedDB data for example.com" + ); + + let dh = new ClearHistoryDialogHelper(); + let promiseSanitized = promiseSanitizationComplete(); + // Create a sandbox for isolated stubbing within the test + let sandbox = sinon.createSandbox(); + sandbox + .stub(SiteDataManager, "getQuotaUsageForTimeRanges") + .callsFake(async () => { + info("stub called"); + + info("This promise should never resolve"); + await new Promise(resolve => {}); + }); + dh.onload = async function () { + // we don't need to initiate a event listener to wait for the resolver to be assigned for this + // test since we do not want the data sizes to load + ok( + !this.win.gSanitizePromptDialog._dataSizesUpdated, + "Data sizes should not be loaded yet" + ); + this.selectDuration(Sanitizer.TIMESPAN_2HOURS); + this.checkPrefCheckbox("cookiesAndStorage", true); + this.acceptDialog(); + }; + dh.onunload = async () => { + await promiseSanitized; + }; + dh.open(); + await dh.promiseClosed; + + // Data for example.org should be cleared + ok( + !(await SiteDataTestUtils.hasIndexedDB("https://example.org")), + "We don't have indexedDB data for example.org" + ); + // Data for example.com should be cleared + ok( + !(await SiteDataTestUtils.hasIndexedDB("https://example.com")), + "We don't have indexedDB data for example.com" + ); + + // Restore the sandbox after the test is complete + sandbox.restore(); +}); diff --git a/browser/base/content/test/sanitize/browser_sanitizeOnShutdown_migration.js b/browser/base/content/test/sanitize/browser_sanitizeOnShutdown_migration.js index 3c2af1d513..bc5c925702 100644 --- a/browser/base/content/test/sanitize/browser_sanitizeOnShutdown_migration.js +++ b/browser/base/content/test/sanitize/browser_sanitizeOnShutdown_migration.js @@ -17,7 +17,7 @@ add_task(async function testMigrationOfCacheAndSiteSettings() { ["privacy.clearOnShutdown.siteSettings", true], ["privacy.clearOnShutdown_v2.cache", false], ["privacy.clearOnShutdown_v2.siteSettings", false], - ["privacy.sanitize.sanitizeOnShutdown.hasMigratedToNewPrefs", false], + ["privacy.sanitize.clearOnShutdown.hasMigratedToNewPrefs", false], ], }); @@ -46,7 +46,7 @@ add_task(async function testMigrationOfCacheAndSiteSettings() { Assert.equal( Services.prefs.getBoolPref( - "privacy.sanitize.sanitizeOnShutdown.hasMigratedToNewPrefs" + "privacy.sanitize.clearOnShutdown.hasMigratedToNewPrefs" ), true, "migration pref has been flipped" @@ -59,7 +59,7 @@ add_task(async function testHistoryAndFormData_historyTrue() { ["privacy.clearOnShutdown.history", true], ["privacy.clearOnShutdown.formdata", false], ["privacy.clearOnShutdown_v2.historyFormDataAndDownloads", false], - ["privacy.sanitize.sanitizeOnShutdown.hasMigratedToNewPrefs", false], + ["privacy.sanitize.clearOnShutdown.hasMigratedToNewPrefs", false], ], }); @@ -85,7 +85,7 @@ add_task(async function testHistoryAndFormData_historyTrue() { Assert.equal( Services.prefs.getBoolPref( - "privacy.sanitize.sanitizeOnShutdown.hasMigratedToNewPrefs" + "privacy.sanitize.clearOnShutdown.hasMigratedToNewPrefs" ), true, "migration pref has been flipped" @@ -98,7 +98,7 @@ add_task(async function testHistoryAndFormData_historyFalse() { ["privacy.clearOnShutdown.history", false], ["privacy.clearOnShutdown.formdata", true], ["privacy.clearOnShutdown_v2.historyFormDataAndDownloads", true], - ["privacy.sanitize.sanitizeOnShutdown.hasMigratedToNewPrefs", false], + ["privacy.sanitize.clearOnShutdown.hasMigratedToNewPrefs", false], ], }); @@ -124,7 +124,7 @@ add_task(async function testHistoryAndFormData_historyFalse() { Assert.equal( Services.prefs.getBoolPref( - "privacy.sanitize.sanitizeOnShutdown.hasMigratedToNewPrefs" + "privacy.sanitize.clearOnShutdown.hasMigratedToNewPrefs" ), true, "migration pref has been flipped" @@ -138,7 +138,7 @@ add_task(async function testCookiesAndStorage_cookiesFalse() { ["privacy.clearOnShutdown.offlineApps", true], ["privacy.clearOnShutdown.sessions", true], ["privacy.clearOnShutdown_v2.cookiesAndStorage", true], - ["privacy.sanitize.sanitizeOnShutdown.hasMigratedToNewPrefs", false], + ["privacy.sanitize.clearOnShutdown.hasMigratedToNewPrefs", false], ], }); @@ -168,7 +168,7 @@ add_task(async function testCookiesAndStorage_cookiesFalse() { Assert.equal( Services.prefs.getBoolPref( - "privacy.sanitize.sanitizeOnShutdown.hasMigratedToNewPrefs" + "privacy.sanitize.clearOnShutdown.hasMigratedToNewPrefs" ), true, "migration pref has been flipped" @@ -182,7 +182,7 @@ add_task(async function testCookiesAndStorage_cookiesTrue() { ["privacy.clearOnShutdown.offlineApps", false], ["privacy.clearOnShutdown.sessions", false], ["privacy.clearOnShutdown_v2.cookiesAndStorage", false], - ["privacy.sanitize.sanitizeOnShutdown.hasMigratedToNewPrefs", false], + ["privacy.sanitize.clearOnShutdown.hasMigratedToNewPrefs", false], ], }); @@ -211,7 +211,7 @@ add_task(async function testCookiesAndStorage_cookiesTrue() { Assert.equal( Services.prefs.getBoolPref( - "privacy.sanitize.sanitizeOnShutdown.hasMigratedToNewPrefs" + "privacy.sanitize.clearOnShutdown.hasMigratedToNewPrefs" ), true, "migration pref has been flipped" @@ -225,7 +225,7 @@ add_task(async function testMigrationDoesNotRepeat() { ["privacy.clearOnShutdown.offlineApps", false], ["privacy.clearOnShutdown.sessions", false], ["privacy.clearOnShutdown_v2.cookiesAndStorage", false], - ["privacy.sanitize.sanitizeOnShutdown.hasMigratedToNewPrefs", true], + ["privacy.sanitize.clearOnShutdown.hasMigratedToNewPrefs", true], ], }); @@ -255,7 +255,7 @@ add_task(async function testMigrationDoesNotRepeat() { Assert.equal( Services.prefs.getBoolPref( - "privacy.sanitize.sanitizeOnShutdown.hasMigratedToNewPrefs" + "privacy.sanitize.clearOnShutdown.hasMigratedToNewPrefs" ), true, "migration pref has been flipped" @@ -273,7 +273,7 @@ add_task(async function ensureNoOldPrefsAreEffectedByMigration() { ["privacy.clearOnShutdown.siteSettings", true], ["privacy.clearOnShutdown.cache", true], ["privacy.clearOnShutdown_v2.cookiesAndStorage", false], - ["privacy.sanitize.sanitizeOnShutdown.hasMigratedToNewPrefs", false], + ["privacy.sanitize.clearOnShutdown.hasMigratedToNewPrefs", false], ], }); diff --git a/browser/base/content/test/sanitize/head.js b/browser/base/content/test/sanitize/head.js index f5a6031b84..30d96c69f6 100644 --- a/browser/base/content/test/sanitize/head.js +++ b/browser/base/content/test/sanitize/head.js @@ -3,10 +3,34 @@ ChromeUtils.defineESModuleGetters(this, { FormHistory: "resource://gre/modules/FormHistory.sys.mjs", PermissionTestUtils: "resource://testing-common/PermissionTestUtils.sys.mjs", PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs", + PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs", + FileTestUtils: "resource://testing-common/FileTestUtils.sys.mjs", Sanitizer: "resource:///modules/Sanitizer.sys.mjs", SiteDataTestUtils: "resource://testing-common/SiteDataTestUtils.sys.mjs", }); +const kMsecPerMin = 60 * 1000; +const kUsecPerMin = kMsecPerMin * 1000; +let today = Date.now() - new Date().setHours(0, 0, 0, 0); +let nowMSec = Date.now(); +let nowUSec = nowMSec * 1000; +const TEST_TARGET_FILE_NAME = "test-download.txt"; +const TEST_QUOTA_USAGE_HOST = "example.com"; +const TEST_QUOTA_USAGE_ORIGIN = "https://" + TEST_QUOTA_USAGE_HOST; +const TEST_QUOTA_USAGE_URL = + getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + TEST_QUOTA_USAGE_ORIGIN + ) + "site_data_test.html"; +const SITE_ORIGINS = [ + "https://www.example.com", + "https://example.org", + "http://localhost:8000", + "http://localhost:3000", +]; + +let fileURL; + function createIndexedDB(host, originAttributes) { let uri = Services.io.newURI("https://" + host); let principal = Services.scriptSecurityManager.createContentPrincipal( @@ -369,3 +393,345 @@ async function createDummyDataForHost(host) { await SiteDataTestUtils.addToIndexedDB(origin); await SiteDataTestUtils.addServiceWorker(dummySWURL); } + +/** + * Helper function to create file URL to open + * + * @returns {Object} a file URL + */ +function createFileURL() { + if (!fileURL) { + let file = Services.dirsvc.get("TmpD", Ci.nsIFile); + file.append("foo.txt"); + file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); + + fileURL = Services.io.newFileURI(file); + } + return fileURL; +} + +/** + * Removes all history visits, downloads, and form entries. + */ +async function blankSlate() { + let publicList = await Downloads.getList(Downloads.PUBLIC); + let downloads = await publicList.getAll(); + for (let download of downloads) { + await publicList.remove(download); + await download.finalize(true); + } + + await FormHistory.update({ op: "remove" }); + await PlacesUtils.history.clear(); +} + +/** + * Adds multiple downloads to the PUBLIC download list + */ +async function addToDownloadList() { + const url = createFileURL(); + const downloadsList = await Downloads.getList(Downloads.PUBLIC); + let timeOptions = [1, 2, 4, 24, 128, 128]; + let buffer = 100000; + + for (let i = 0; i < timeOptions.length; i++) { + let timeDownloaded = 60 * kMsecPerMin * timeOptions[i]; + if (timeOptions[i] === 24) { + timeDownloaded = today; + } + + let download = await Downloads.createDownload({ + source: { url: url.spec, isPrivate: false }, + target: { path: FileTestUtils.getTempFile(TEST_TARGET_FILE_NAME).path }, + startTime: { + getTime: _ => { + return nowMSec - timeDownloaded + buffer; + }, + }, + }); + + Assert.ok(!!download); + downloadsList.add(download); + } + let items = await downloadsList.getAll(); + Assert.equal(items.length, 6, "Items were added to the list"); +} + +async function addToSiteUsage() { + // Fill indexedDB with test data. + // Don't wait for the page to load, to register the content event handler as quickly as possible. + // If this test goes intermittent, we might have to tell the page to wait longer before + // firing the event. + BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_QUOTA_USAGE_URL, false); + await BrowserTestUtils.waitForContentEvent( + gBrowser.selectedBrowser, + "test-indexedDB-done", + false, + null, + true + ); + BrowserTestUtils.removeTab(gBrowser.selectedTab); + + let siteLastAccessed = [1, 2, 4, 24]; + + let staticUsage = 4096 * 6; + // Add a time buffer so the site access falls within the time range + const buffer = 10000; + + // Change lastAccessed of sites + for (let index = 0; index < siteLastAccessed.length; index++) { + let lastAccessedTime = 60 * kMsecPerMin * siteLastAccessed[index]; + if (siteLastAccessed[index] === 24) { + lastAccessedTime = today; + } + + let site = SiteDataManager._testInsertSite(SITE_ORIGINS[index], { + quotaUsage: staticUsage, + lastAccessed: (nowMSec - lastAccessedTime + buffer) * 1000, + }); + Assert.ok(site, "Site added successfully"); + } +} + +function promiseSanitizationComplete() { + return TestUtils.topicObserved("sanitizer-sanitization-complete"); +} + +/** + * This wraps the dialog and provides some convenience methods for interacting + * with it. + * + * @param {Window} browserWin (optional) + * The browser window that the dialog is expected to open in. If not + * supplied, the initial browser window of the test run is used. + * @param {Object} {mode, checkingDataSizes} + * mode: context to open the dialog in + * One of + * clear on shutdown settings context ("clearOnShutdown"), + * clear site data settings context ("clearSiteData"), + * clear history context ("clearHistory"), + * browser context ("browser") + * "browser" by default + * checkingDataSizes: boolean check if we should wait for the data sizes + * to load + * + */ +function ClearHistoryDialogHelper({ + mode = "browser", + checkingDataSizes = false, +} = {}) { + this._browserWin = window; + this.win = null; + this._mode = mode; + this._checkingDataSizes = checkingDataSizes; + this.promiseClosed = new Promise(resolve => { + this._resolveClosed = resolve; + }); +} + +ClearHistoryDialogHelper.prototype = { + /** + * "Presses" the dialog's OK button. + */ + acceptDialog() { + let dialogEl = this.win.document.querySelector("dialog"); + is( + dialogEl.getButton("accept").disabled, + false, + "Dialog's OK button should not be disabled" + ); + dialogEl.acceptDialog(); + }, + + /** + * "Presses" the dialog's Cancel button. + */ + cancelDialog() { + this.win.document.querySelector("dialog").cancelDialog(); + }, + + /** + * (Un)checks a history scope checkbox (browser & download history, + * form history, etc.). + * + * @param aPrefName + * The final portion of the checkbox's privacy.cpd.* preference name + * @param aCheckState + * True if the checkbox should be checked, false otherwise + */ + checkPrefCheckbox(aPrefName, aCheckState) { + var cb = this.win.document.querySelectorAll( + "checkbox[id='" + aPrefName + "']" + ); + is(cb.length, 1, "found checkbox for " + aPrefName + " id"); + if (cb[0].checked != aCheckState) { + cb[0].click(); + } + }, + + /** + * @param {String} aCheckboxId + * The checkbox id name + * @param {Boolean} aCheckState + * True if the checkbox should be checked, false otherwise + */ + validateCheckbox(aCheckboxId, aCheckState) { + let cb = this.win.document.querySelectorAll( + "checkbox[id='" + aCheckboxId + "']" + ); + is(cb.length, 1, `found checkbox for id=${aCheckboxId}`); + is( + cb[0].checked, + aCheckState, + `checkbox for ${aCheckboxId} is ${aCheckState}` + ); + }, + + /** + * Makes sure all the checkboxes are checked. + */ + _checkAllCheckboxesCustom(check) { + var cb = this.win.document.querySelectorAll(".clearingItemCheckbox"); + ok(cb.length, "found checkboxes for ids"); + for (var i = 0; i < cb.length; ++i) { + if (cb[i].checked != check) { + cb[i].click(); + } + } + }, + + checkAllCheckboxes() { + this._checkAllCheckboxesCustom(true); + }, + + uncheckAllCheckboxes() { + this._checkAllCheckboxesCustom(false); + }, + + /** + * @return The dialog's duration dropdown + */ + getDurationDropdown() { + return this.win.document.getElementById("sanitizeDurationChoice"); + }, + + /** + * @return The clear-everything warning box + */ + getWarningPanel() { + return this.win.document.getElementById("sanitizeEverythingWarningBox"); + }, + + /** + * @return True if the "Everything" warning panel is visible (as opposed to + * the tree) + */ + isWarningPanelVisible() { + return !this.getWarningPanel().hidden; + }, + + /** + * Opens the clear recent history dialog. Before calling this, set + * this.onload to a function to execute onload. It should close the dialog + * when done so that the tests may continue. Set this.onunload to a function + * to execute onunload. this.onunload is optional. If it returns true, the + * caller is expected to call promiseAsyncUpdates at some point; if false is + * returned, promiseAsyncUpdates is called automatically. + */ + async open() { + let dialogPromise = BrowserTestUtils.promiseAlertDialogOpen( + null, + "chrome://browser/content/sanitize_v2.xhtml", + { + isSubDialog: true, + } + ); + + // We want to simulate opening the dialog inside preferences for clear history + // and clear site data + if (this._mode != "browser") { + await openPreferencesViaOpenPreferencesAPI("privacy", { + leaveOpen: true, + }); + let tabWindow = gBrowser.selectedBrowser.contentWindow; + let clearDialogOpenButtonId = this._mode + "Button"; + // the id for clear on shutdown is of a different format + if (this._mode == "clearOnShutdown") { + // set always clear to true to enable the clear on shutdown dialog + let enableSettingsCheckbox = + tabWindow.document.getElementById("alwaysClear"); + if (!enableSettingsCheckbox.checked) { + enableSettingsCheckbox.click(); + } + clearDialogOpenButtonId = "clearDataSettings"; + } + // open dialog + tabWindow.document.getElementById(clearDialogOpenButtonId).click(); + } + // We open the dialog in the chrome context in other cases + else { + executeSoon(() => { + Sanitizer.showUI(this._browserWin, this._mode); + }); + } + + this.win = await dialogPromise; + this.win.addEventListener( + "load", + () => { + // Run onload on next tick so that gSanitizePromptDialog.init can run first. + executeSoon(async () => { + if (this._checkingDataSizes) { + // we wait for the data sizes to load to avoid async errors when validating sizes + await this.win.gSanitizePromptDialog + .dataSizesFinishedUpdatingPromise; + } + this.onload(); + }); + }, + { once: true } + ); + this.win.addEventListener( + "unload", + () => { + // Some exceptions that reach here don't reach the test harness, but + // ok()/is() do... + (async () => { + if (this.onunload) { + await this.onunload(); + } + if (this._mode != "browser") { + BrowserTestUtils.removeTab(gBrowser.selectedTab); + } + await PlacesTestUtils.promiseAsyncUpdates(); + this._resolveClosed(); + this.win = null; + })(); + }, + { once: true } + ); + }, + + /** + * Selects a duration in the duration dropdown. + * + * @param aDurVal + * One of the Sanitizer.TIMESPAN_* values + */ + selectDuration(aDurVal) { + this.getDurationDropdown().value = aDurVal; + if (aDurVal === Sanitizer.TIMESPAN_EVERYTHING) { + is( + this.isWarningPanelVisible(), + true, + "Warning panel should be visible for TIMESPAN_EVERYTHING" + ); + } else { + is( + this.isWarningPanelVisible(), + false, + "Warning panel should not be visible for non-TIMESPAN_EVERYTHING" + ); + } + }, +}; diff --git a/browser/base/content/test/siteIdentity/browser.toml b/browser/base/content/test/siteIdentity/browser.toml index f0b6191302..c075052fa5 100644 --- a/browser/base/content/test/siteIdentity/browser.toml +++ b/browser/base/content/test/siteIdentity/browser.toml @@ -106,6 +106,12 @@ skip-if = [ ["browser_identity_UI.js"] https_first_disabled = true +["browser_identity_web_controlled_blank.js"] +support-files = [ + "test_web_controlled_blank.html", + "dummy_page.html", +] + ["browser_iframe_navigation.js"] https_first_disabled = true support-files = ["iframe_navigation.html"] diff --git a/browser/base/content/test/siteIdentity/browser_identity_web_controlled_blank.js b/browser/base/content/test/siteIdentity/browser_identity_web_controlled_blank.js new file mode 100644 index 0000000000..01eca12178 --- /dev/null +++ b/browser/base/content/test/siteIdentity/browser_identity_web_controlled_blank.js @@ -0,0 +1,128 @@ +/* + * This work is marked with CC0 1.0. To view a copy of this license, + * visit http://creativecommons.org/publicdomain/zero/1.0 + * + * + * Tests for correct behaviour of web-controlled about:blank pages in identity panel. + * Getting into a testable state is different enough that we test all the behaviors here + * separately, rather than with the usual (secure, insecure, etc.) cases + */ + +const TEST_HOST = "example.com"; +const TEST_ORIGIN = "https://" + TEST_HOST; +const TEST_PATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + TEST_ORIGIN +); +const LOCALHOST_PATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://127.0.0.1:8888" +); +const TEST_URI = TEST_PATH + "test_web_controlled_blank.html"; +const DUMMY_URI = LOCALHOST_PATH + "dummy_page.html"; + +// Open a new tab of `test_web_controlled_blank.html` and click +// an element with a particular ID to open an about:blank popup +// that is controlled by that first tab. +// +// Then test that the UI elements are all correct. And make sure +// we don't have anything odd going on after navigating away in the +// popup. +async function web_controlled_about_blank_helper(id_to_click) { + // Open a new tab that will control about:blank pages + await BrowserTestUtils.withNewTab(TEST_URI, async browser => { + // Open a new popup by clicking the provided id_to_click from the content + let popupWindowPromise = BrowserTestUtils.waitForNewWindow(); + await SpecialPowers.spawn(browser, [id_to_click], async function (id) { + content.document.getElementById(id).click(); + }); + let popupWindow = await popupWindowPromise; + + // Validate the icon in the urlbar + let identityIcon = popupWindow.document.querySelector("#identity-icon"); + let identityIconImageURL = popupWindow + .getComputedStyle(identityIcon) + .getPropertyValue("list-style-image"); + is( + identityIconImageURL, + `url("chrome://global/skin/icons/info.svg")`, + "The identity icon has a correct image url." + ); + + // Open the identity panel + let popupShown = BrowserTestUtils.waitForEvent( + popupWindow, + "popupshown", + true, + event => event.target == popupWindow.gIdentityHandler._identityPopup + ); + popupWindow.gIdentityHandler._identityIconBox.click(); + info("Waiting for the Control Center to be shown"); + await popupShown; + ok( + !popupWindow.gIdentityHandler._identityPopup.hidden, + "Control Center is visible" + ); + + // Validate that the predecessor is shown in the identity panel + ok( + popupWindow.gIdentityHandler._identityPopupMainViewHeaderLabel.textContent.includes( + TEST_HOST + ), + "Identity UI header shows the host of the predecessor" + ); + + // Validate that the correct message is displayed + is( + popupWindow.gIdentityHandler._identityPopup.getAttribute("connection"), + "associated", + "Identity UI shows associated message." + ); + + // Validate that there is no additional security info + let securityButton = popupWindow.gBrowser.ownerDocument.querySelector( + "#identity-popup-security-button" + ); + is( + securityButton.disabled, + true, + "Security button has correct disabled state" + ); + + // Navigate away to a localhost page and make sure the identity icon changes + let loaded = BrowserTestUtils.browserLoaded( + popupWindow.gBrowser.selectedBrowser, + false, + DUMMY_URI + ); + await SpecialPowers.spawn( + popupWindow.gBrowser.selectedBrowser, + [DUMMY_URI], + async function (uri) { + content.location = uri; + } + ); + info("Waiting for the navigation to a dummy page to complete."); + await loaded; + + identityIconImageURL = popupWindow.gBrowser.ownerGlobal + .getComputedStyle(identityIcon) + .getPropertyValue("list-style-image"); + is( + identityIconImageURL, + `url("chrome://global/skin/icons/page-portrait.svg")`, + "The identity icon has a correct image url after navigating away." + ); + + // Exit this test, cleaning up as we go. + await BrowserTestUtils.closeWindow(popupWindow); + }); +} + +add_task(async function test_document_write() { + await web_controlled_about_blank_helper("document_write"); +}); + +add_task(async function test_innerHTML() { + await web_controlled_about_blank_helper("innerhtml"); +}); diff --git a/browser/base/content/test/siteIdentity/test_web_controlled_blank.html b/browser/base/content/test/siteIdentity/test_web_controlled_blank.html new file mode 100644 index 0000000000..35c1fd4ca2 --- /dev/null +++ b/browser/base/content/test/siteIdentity/test_web_controlled_blank.html @@ -0,0 +1,36 @@ +<!doctype html> +<html> + <head> + <title>Bug 1813463: Web controlled about:blank</title> + </head> + <!-- + This work is marked with CC0 1.0. To view a copy of this license, + visit http://creativecommons.org/publicdomain/zero/1.0 + --> + <body> + <p><a href="#" id="document_write">document.write example</a></p> + <p><a href="#" id="innerhtml">innerHTML example</a></p> + + <script> + document.getElementById("document_write").addEventListener("click", function (aEvent) { + aEvent.preventDefault(); + let popup = window.open("about:blank", "_blank", "width=800,height=600,popup"); + popup.document.write(` + <h1>check security info</h1> + <p>initial window.location = ${popup.location}</p> + <script> + document.write("<p>new window.location = " + window.location + "</p>") + <${"/"}script> + `); + }); + document.getElementById("innerhtml").addEventListener("click", function (aEvent) { + aEvent.preventDefault(); + let popup = window.open("about:blank", "_blank", "width=800,height=600,popup"); + popup.stop(); + popup.document.body.innerHTML = ` + <h1>check security info</h1> + <p>window.location = ${popup.location}</p>`; + }); + </script> + </body> +</html> diff --git a/browser/base/content/test/static/browser_all_files_referenced.js b/browser/base/content/test/static/browser_all_files_referenced.js index 6389e59e00..5e83443ec7 100644 --- a/browser/base/content/test/static/browser_all_files_referenced.js +++ b/browser/base/content/test/static/browser_all_files_referenced.js @@ -76,6 +76,9 @@ var gExceptionPaths = [ // Localization file added programatically in FeatureCallout.sys.mjs "resource://app/localization/en-US/browser/featureCallout.ftl", + // Localization file added programatically in ContentAnalysis.sys.mjs + "resource://gre/localization/en-US/toolkit/contentanalysis/", + // CSS files are referenced inside JS in an html template "chrome://browser/content/aboutlogins/components/", ]; @@ -277,6 +280,9 @@ var allowlist = [ // find the references) { file: "chrome://browser/content/screenshots/copied-notification.svg" }, + // Bug 1875361 + { file: "chrome://global/content/ml/SummarizerModel.sys.mjs" }, + // toolkit/xre/MacRunFromDmgUtils.mm { file: "resource://gre/localization/en-US/toolkit/global/run-from-dmg.ftl" }, @@ -871,9 +877,6 @@ add_task(async function checkAllTheFiles() { // Wait for all manifest to be parsed await PerfTestHelpers.throttledMapPromises(manifestURIs, parseManifest); - for (let jsm of Components.manager.getComponentJSMs()) { - gReferencesFromCode.set(jsm, null); - } for (let esModule of Components.manager.getComponentESModules()) { gReferencesFromCode.set(esModule, null); } diff --git a/browser/base/content/test/static/browser_misused_characters_in_strings.js b/browser/base/content/test/static/browser_misused_characters_in_strings.js index 4191cc966e..c234f8107e 100644 --- a/browser/base/content/test/static/browser_misused_characters_in_strings.js +++ b/browser/base/content/test/static/browser_misused_characters_in_strings.js @@ -68,6 +68,28 @@ let gExceptionsList = [ key: "MathML_DeprecatedMathVariantWarning", type: "single-quote", }, + // These error messages contain references to the CSP keywords 'unsafe-eval'/'wasm-unsafe-eval', + // and those keywords contain actual single-quotes: https://w3c.github.io/webappsec-csp/#grammardef-keyword-source + { + file: "csp.properties", + key: "CSPEvalScriptViolation", + type: "single-quote", + }, + { + file: "csp.properties", + key: "CSPROEvalScriptViolation", + type: "single-quote", + }, + { + file: "csp.properties", + key: "CSPWasmEvalScriptViolation", + type: "single-quote", + }, + { + file: "csp.properties", + key: "CSPROWasmEvalScriptViolation", + type: "single-quote", + }, ]; /** diff --git a/browser/base/content/test/static/browser_parsable_css.js b/browser/base/content/test/static/browser_parsable_css.js index b34ae7d9c1..602cc5a7e2 100644 --- a/browser/base/content/test/static/browser_parsable_css.js +++ b/browser/base/content/test/static/browser_parsable_css.js @@ -68,24 +68,6 @@ if (!Services.prefs.getBoolPref("layout.css.zoom.enabled")) { }); } -if (!Services.prefs.getBoolPref("layout.css.math-depth.enabled")) { - // mathml.css UA sheet rule for math-depth. - ignoreList.push({ - sourceName: /\b(scrollbars|mathml)\.css$/i, - errorMessage: /Unknown property .*\bmath-depth\b/i, - isFromDevTools: false, - }); -} - -if (!Services.prefs.getBoolPref("layout.css.math-style.enabled")) { - // mathml.css UA sheet rule for math-style. - ignoreList.push({ - sourceName: /(?:res|gre-resources)\/mathml\.css$/i, - errorMessage: /Unknown property .*\bmath-style\b/i, - isFromDevTools: false, - }); -} - if (!Services.prefs.getBoolPref("layout.css.scroll-anchoring.enabled")) { ignoreList.push({ sourceName: /webconsole\.css$/i, diff --git a/browser/base/content/test/tabPrompts/browser_beforeunload_urlbar.js b/browser/base/content/test/tabPrompts/browser_beforeunload_urlbar.js index 52044b5874..1466e9ca86 100644 --- a/browser/base/content/test/tabPrompts/browser_beforeunload_urlbar.js +++ b/browser/base/content/test/tabPrompts/browser_beforeunload_urlbar.js @@ -9,11 +9,6 @@ const TEST_ROOT = getRootDirectory(gTestPath).replace( "http://example.com" ); -const CONTENT_PROMPT_SUBDIALOG = Services.prefs.getBoolPref( - "prompts.contentPromptSubDialog", - false -); - add_task(async function test_beforeunload_stay_clears_urlbar() { await SpecialPowers.pushPrefEnv({ set: [["dom.require_user_interaction_for_beforeunload", false]], @@ -27,27 +22,10 @@ add_task(async function test_beforeunload_stay_clears_urlbar() { gURLBar.value = inputValue.slice(0, -1); EventUtils.sendString(inputValue.slice(-1)); - if (CONTENT_PROMPT_SUBDIALOG) { - let promptOpenedPromise = - BrowserTestUtils.promiseAlertDialogOpen("cancel"); - EventUtils.synthesizeKey("VK_RETURN"); - await promptOpenedPromise; - await TestUtils.waitForTick(); - } else { - let promptOpenedPromise = TestUtils.topicObserved( - "tabmodal-dialog-loaded" - ); - EventUtils.synthesizeKey("VK_RETURN"); - await promptOpenedPromise; - let promptElement = browser.parentNode.querySelector("tabmodalprompt"); - - // Click the cancel button - promptElement.querySelector(".tabmodalprompt-button1").click(); - await TestUtils.waitForCondition( - () => promptElement.parentNode == null, - "tabprompt should be removed" - ); - } + let promptOpenedPromise = BrowserTestUtils.promiseAlertDialogOpen("cancel"); + EventUtils.synthesizeKey("VK_RETURN"); + await promptOpenedPromise; + await TestUtils.waitForTick(); // Can't just compare directly with TEST_URL because the URL may be trimmed. // Just need it to not be the example.org thing we typed in. diff --git a/browser/base/content/test/tabPrompts/browser_confirmFolderUpload.js b/browser/base/content/test/tabPrompts/browser_confirmFolderUpload.js index 62b0ed4f2b..52596095c4 100644 --- a/browser/base/content/test/tabPrompts/browser_confirmFolderUpload.js +++ b/browser/base/content/test/tabPrompts/browser_confirmFolderUpload.js @@ -88,7 +88,7 @@ async function testUploadPrompt(confirmUpload) { await ContentTask.spawn(browser, { path }, args => { let MockFilePicker = content.SpecialPowers.MockFilePicker; MockFilePicker.init( - content, + content.browsingContext, "A Mock File Picker", content.SpecialPowers.Ci.nsIFilePicker.modeGetFolder ); diff --git a/browser/base/content/test/tabPrompts/browser_contentOrigins.js b/browser/base/content/test/tabPrompts/browser_contentOrigins.js index 10c8809490..2bf4ba6039 100644 --- a/browser/base/content/test/tabPrompts/browser_contentOrigins.js +++ b/browser/base/content/test/tabPrompts/browser_contentOrigins.js @@ -129,11 +129,7 @@ async function checkDialog( add_setup(async function () { await SpecialPowers.pushPrefEnv({ - set: [ - ["prompts.contentPromptSubDialog", true], - ["prompts.modalType.httpAuth", Ci.nsIPrompt.MODAL_TYPE_TAB], - ["prompts.tabChromePromptSubDialog", true], - ], + set: [["prompts.modalType.httpAuth", Ci.nsIPrompt.MODAL_TYPE_TAB]], }); }); diff --git a/browser/base/content/test/tabPrompts/browser_multiplePrompts.js b/browser/base/content/test/tabPrompts/browser_multiplePrompts.js index 597b7dfd6f..65c8b3eff4 100644 --- a/browser/base/content/test/tabPrompts/browser_multiplePrompts.js +++ b/browser/base/content/test/tabPrompts/browser_multiplePrompts.js @@ -1,13 +1,7 @@ "use strict"; -const CONTENT_PROMPT_SUBDIALOG = Services.prefs.getBoolPref( - "prompts.contentPromptSubDialog", - false -); - /** - * Goes through a stacked series of dialogs opened with - * CONTENT_PROMPT_SUBDIALOG set to true, and ensures that + * Goes through a stacked series of dialogs and ensures that * the oldest one is front-most and has the right type. It * then closes the oldest to newest dialog. * @@ -58,64 +52,6 @@ async function closeDialogs(tab, dialogCount) { is(dialogs.length, 0, "Dialogs should all be dismissed."); } -/** - * Goes through a stacked series of tabprompt modals opened with - * CONTENT_PROMPT_SUBDIALOG set to false, and ensures that - * the oldest one is front-most and has the right type. It also - * ensures that the other tabprompt modals are hidden. It - * then closes the oldest to newest dialog. - * - * @param {Element} tab The <tab> that has had tabprompt modals opened - * for it. - * @param {Number} promptCount How many modals we expected to have been - * opened. - * - * @return {Promise} - * @resolves {undefined} Once the modals have all been closed. - */ -async function closeTabModals(tab, promptCount) { - let promptElementsCount = promptCount; - while (promptElementsCount--) { - let promptElements = - tab.linkedBrowser.parentNode.querySelectorAll("tabmodalprompt"); - is( - promptElements.length, - promptElementsCount + 1, - "There should be " + (promptElementsCount + 1) + " prompt(s)." - ); - // The oldest should be the first. - let i = 0; - - for (let promptElement of promptElements) { - let prompt = tab.linkedBrowser.tabModalPromptBox.getPrompt(promptElement); - let expectedType = ["alert", "prompt", "confirm"][i % 3]; - is( - prompt.Dialog.args.text, - expectedType + " countdown #" + i, - "The #" + i + " alert should be labelled as such." - ); - if (i !== promptElementsCount) { - is(prompt.element.hidden, true, "This prompt should be hidden."); - i++; - continue; - } - - is(prompt.element.hidden, false, "The last prompt should not be hidden."); - prompt.onButtonClick(0); - - // The click is handled async; wait for an event loop turn for that to - // happen. - await new Promise(function (resolve) { - Services.tm.dispatchToMainThread(resolve); - }); - } - } - - let promptElements = - tab.linkedBrowser.parentNode.querySelectorAll("tabmodalprompt"); - is(promptElements.length, 0, "Prompts should all be dismissed."); -} - /* * This test triggers multiple alerts on one single tab, because it"s possible * for web content to do so. The behavior is described in bug 1266353. @@ -161,11 +97,7 @@ add_task(async function () { await promptsOpenedPromise; - if (CONTENT_PROMPT_SUBDIALOG) { - await closeDialogs(tab, PROMPTCOUNT); - } else { - await closeTabModals(tab, PROMPTCOUNT); - } + await closeDialogs(tab, PROMPTCOUNT); BrowserTestUtils.removeTab(tab); }); diff --git a/browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js b/browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js index 6b116b71f9..2fa3752881 100644 --- a/browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js +++ b/browser/base/content/test/tabPrompts/browser_openPromptInBackgroundTab.js @@ -22,118 +22,7 @@ registerCleanupFunction(function () { * the user to enable this automatically re-selecting. We then check that * checking the checkbox does actually enable that behaviour. */ -add_task(async function test_old_modal_ui() { - // We're intentionally testing the old modal mechanism, so disable the new one. - await SpecialPowers.pushPrefEnv({ - set: [["prompts.contentPromptSubDialog", false]], - }); - - let firstTab = gBrowser.selectedTab; - // load page that opens prompt when page is hidden - let openedTab = await BrowserTestUtils.openNewForegroundTab( - gBrowser, - pageWithAlert, - true - ); - let openedTabGotAttentionPromise = BrowserTestUtils.waitForAttribute( - "attention", - openedTab - ); - // switch away from that tab again - this triggers the alert. - await BrowserTestUtils.switchTab(gBrowser, firstTab); - // ... but that's async on e10s... - await openedTabGotAttentionPromise; - // check for attention attribute - is( - openedTab.hasAttribute("attention"), - true, - "Tab with alert should have 'attention' attribute." - ); - ok(!openedTab.selected, "Tab with alert should not be selected"); - - // switch tab back, and check the checkbox is displayed: - await BrowserTestUtils.switchTab(gBrowser, openedTab); - // check the prompt is there, and the extra row is present - let promptElements = - openedTab.linkedBrowser.parentNode.querySelectorAll("tabmodalprompt"); - is(promptElements.length, 1, "There should be 1 prompt"); - let ourPromptElement = promptElements[0]; - let checkbox = ourPromptElement.querySelector( - "checkbox[label*='example.com']" - ); - ok(checkbox, "The checkbox should be there"); - ok(!checkbox.checked, "Checkbox shouldn't be checked"); - // tick box and accept dialog - checkbox.checked = true; - let ourPrompt = - openedTab.linkedBrowser.tabModalPromptBox.getPrompt(ourPromptElement); - ourPrompt.onButtonClick(0); - // Wait for that click to actually be handled completely. - await new Promise(function (resolve) { - Services.tm.dispatchToMainThread(resolve); - }); - // check permission is set - is( - Services.perms.ALLOW_ACTION, - PermissionTestUtils.testPermission(pageWithAlert, "focus-tab-by-prompt"), - "Tab switching should now be allowed" - ); - - // Check if the control center shows the correct permission. - let shown = BrowserTestUtils.waitForEvent( - window, - "popupshown", - true, - event => event.target == gPermissionPanel._permissionPopup - ); - gPermissionPanel._identityPermissionBox.click(); - await shown; - let labelText = SitePermissions.getPermissionLabel("focus-tab-by-prompt"); - let permissionsList = document.getElementById( - "permission-popup-permission-list" - ); - let label = permissionsList.querySelector( - ".permission-popup-permission-label" - ); - is(label.textContent, labelText); - gPermissionPanel._permissionPopup.hidePopup(); - - // Check if the identity icon signals granted permission. - ok( - gPermissionPanel._identityPermissionBox.hasAttribute("hasPermissions"), - "identity-box signals granted permissions" - ); - - let openedTabSelectedPromise = BrowserTestUtils.waitForAttribute( - "selected", - openedTab, - "true" - ); - // switch to other tab again - await BrowserTestUtils.switchTab(gBrowser, firstTab); - - // This is sync in non-e10s, but in e10s we need to wait for this, so yield anyway. - // Note that the switchTab promise doesn't actually guarantee anything about *which* - // tab ends up as selected when its event fires, so using that here wouldn't work. - await openedTabSelectedPromise; - // should be switched back - ok(openedTab.selected, "Ta-dah, the other tab should now be selected again!"); - - // In e10s, with the conformant promise scheduling, we have to wait for next tick - // to ensure that the prompt is open before removing the opened tab, because the - // promise callback of 'openedTabSelectedPromise' could be done at the middle of - // RemotePrompt.openTabPrompt() while 'DOMModalDialogClosed' event is fired. - await TestUtils.waitForTick(); - - BrowserTestUtils.removeTab(openedTab); -}); - -add_task(async function test_new_modal_ui() { - // We're intentionally testing the new modal mechanism, so make sure it's enabled. - await SpecialPowers.pushPrefEnv({ - set: [["prompts.contentPromptSubDialog", true]], - }); - +add_task(async function test_modal_ui() { // Make sure we clear the focus tab permission set in the previous test PermissionTestUtils.remove(pageWithAlert, "focus-tab-by-prompt"); diff --git a/browser/base/content/test/tabdialogs/browser_tabdialogbox_content_prompts.js b/browser/base/content/test/tabdialogs/browser_tabdialogbox_content_prompts.js index 50b94e1a36..5cac19f6af 100644 --- a/browser/base/content/test/tabdialogs/browser_tabdialogbox_content_prompts.js +++ b/browser/base/content/test/tabdialogs/browser_tabdialogbox_content_prompts.js @@ -3,7 +3,6 @@ "use strict"; -const CONTENT_PROMPT_PREF = "prompts.contentPromptSubDialog"; const TEST_ROOT_CHROME = getRootDirectory(gTestPath); const TEST_DIALOG_PATH = TEST_ROOT_CHROME + "subdialog.xhtml"; @@ -41,13 +40,6 @@ var commonDialogsBundle = Services.strings.createBundle( "chrome://global/locale/commonDialogs.properties" ); -// Setup. -add_setup(async function () { - await SpecialPowers.pushPrefEnv({ - set: [[CONTENT_PROMPT_PREF, true]], - }); -}); - /** * Test that a manager for content prompts is added to tab dialog box. */ diff --git a/browser/base/content/test/tabs/browser.toml b/browser/base/content/test/tabs/browser.toml index 8008d70f0c..1b4a6900bf 100644 --- a/browser/base/content/test/tabs/browser.toml +++ b/browser/base/content/test/tabs/browser.toml @@ -236,7 +236,6 @@ support-files = [ ] ["browser_overflowScroll.js"] -fail-if = ["a11y_checks"] # Bugs 1854233 and 1873049 scrollbutton-down/up are not labeled skip-if = [ "win11_2009", # Bug 1797751 ] diff --git a/browser/base/content/test/tabs/browser_close_during_beforeunload.js b/browser/base/content/test/tabs/browser_close_during_beforeunload.js index 32bbb65b62..035884d713 100644 --- a/browser/base/content/test/tabs/browser_close_during_beforeunload.js +++ b/browser/base/content/test/tabs/browser_close_during_beforeunload.js @@ -4,14 +4,7 @@ // beforeunload confirmation ignores the beforeunload listener and // unblocks the original close call. -const CONTENT_PROMPT_SUBDIALOG = Services.prefs.getBoolPref( - "prompts.contentPromptSubDialog", - false -); - -const DIALOG_TOPIC = CONTENT_PROMPT_SUBDIALOG - ? "common-dialog-loaded" - : "tabmodal-dialog-loaded"; +const DIALOG_TOPIC = "common-dialog-loaded"; add_task(async function () { await SpecialPowers.pushPrefEnv({ diff --git a/browser/base/content/test/tabs/browser_multiselect_tabs_bookmark.js b/browser/base/content/test/tabs/browser_multiselect_tabs_bookmark.js index a24e72c0bb..cd3728edcd 100644 --- a/browser/base/content/test/tabs/browser_multiselect_tabs_bookmark.js +++ b/browser/base/content/test/tabs/browser_multiselect_tabs_bookmark.js @@ -48,11 +48,6 @@ add_task(async function test() { false, "Bookmark Selected Tabs is hidden" ); - is( - PlacesCommandHook.uniqueSelectedPages.length, - 1, - "No more than one unique selected page" - ); info("Add a different page to selection"); let tab4 = await addTab_example_com(); @@ -69,11 +64,6 @@ add_task(async function test() { false, "Bookmark Selected Tabs is hidden" ); - is( - PlacesCommandHook.uniqueSelectedPages.length, - 2, - "More than one unique selected page" - ); for (let tab of [tab1, tab2, tab3, tab4]) { BrowserTestUtils.removeTab(tab); diff --git a/browser/base/content/test/tabs/browser_tab_preview.js b/browser/base/content/test/tabs/browser_tab_preview.js index e3dd1b6842..718afbb940 100644 --- a/browser/base/content/test/tabs/browser_tab_preview.js +++ b/browser/base/content/test/tabs/browser_tab_preview.js @@ -34,7 +34,7 @@ add_setup(async function () { set: [ ["browser.tabs.cardPreview.enabled", true], ["browser.tabs.cardPreview.showThumbnails", false], - ["browser.tabs.cardPreview.delayMs", 0], + ["ui.tooltip.delay_ms", 0], ], }); }); @@ -46,7 +46,7 @@ add_setup(async function () { * 2. Tab preview card shows the correct preview for the tab being hovered * 3. Tab preview card is dismissed when the mouse leaves the tab bar */ -add_task(async () => { +add_task(async function hoverTests() { const tabUrl1 = "data:text/html,<html><head><title>First New Tab</title></head><body>Hello</body></html>"; const tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl1); @@ -85,6 +85,11 @@ add_task(async () => { BrowserTestUtils.removeTab(tab1); BrowserTestUtils.removeTab(tab2); + + // Move the mouse outside of the tab strip. + EventUtils.synthesizeMouseAtCenter(document.documentElement, { + type: "mouseover", + }); }); /** @@ -92,7 +97,7 @@ add_task(async () => { * when browser.tabs.cardPreview.showThumbnails is set to true, * while the currently selected tab never displays a thumbnail in its preview. */ -add_task(async () => { +add_task(async function thumbnailTests() { await SpecialPowers.pushPrefEnv({ set: [["browser.tabs.cardPreview.showThumbnails", true]], }); @@ -120,15 +125,28 @@ add_task(async () => { "Tab2 (selected) does not contain thumbnail" ); + const previewHidden = BrowserTestUtils.waitForEvent( + document.getElementById("tabbrowser-tab-preview"), + "previewhidden" + ); + BrowserTestUtils.removeTab(tab1); BrowserTestUtils.removeTab(tab2); await SpecialPowers.popPrefEnv(); + + // Removing the tab should close the preview. + await previewHidden; + + // Move the mouse outside of the tab strip. + EventUtils.synthesizeMouseAtCenter(document.documentElement, { + type: "mouseover", + }); }); /** * Wheel events at the document-level of the window should hide the preview. */ -add_task(async () => { +add_task(async function wheelTests() { const tabUrl1 = "about:blank"; const tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, tabUrl1); const tabUrl2 = "about:blank"; @@ -141,14 +159,49 @@ add_task(async () => { document.getElementById("tabbrowser-tab-preview"), "previewhidden" ); - EventUtils.synthesizeMouse(tabs, 0, tabs.outerHeight + 1, { - wheel: true, - deltaY: -1, - deltaMode: WheelEvent.DOM_DELTA_LINE, - }); + + // Copied from apz_test_native_event_utils.js + let message = 0; + switch (AppConstants.platform) { + case "win": + message = 0x020a; + break; + case "linux": + message = 4; + break; + case "macosx": + message = 1; + break; + } + + let rect = tabs.getBoundingClientRect(); + let screenRect = window.windowUtils.toScreenRect( + rect.x, + rect.y, + rect.width, + rect.height + ); + window.windowUtils.sendNativeMouseScrollEvent( + screenRect.left, + screenRect.bottom, + message, + 0, + 3, + 0, + 0, + Ci.nsIDOMWindowUtils.MOUSESCROLL_SCROLL_LINES, + tabs, + null + ); + await previewHidden; BrowserTestUtils.removeTab(tab1); BrowserTestUtils.removeTab(tab2); await SpecialPowers.popPrefEnv(); + + // Move the mouse outside of the tab strip. + EventUtils.synthesizeMouseAtCenter(document.documentElement, { + type: "mouseover", + }); }); diff --git a/browser/base/content/test/webextensions/browser_permissions_local_file.js b/browser/base/content/test/webextensions/browser_permissions_local_file.js index a2fdc34db3..7f8f256e14 100644 --- a/browser/base/content/test/webextensions/browser_permissions_local_file.js +++ b/browser/base/content/test/webextensions/browser_permissions_local_file.js @@ -10,7 +10,7 @@ async function installFile(filename) { file.leafName = filename; let MockFilePicker = SpecialPowers.MockFilePicker; - MockFilePicker.init(window); + MockFilePicker.init(window.browsingContext); MockFilePicker.setFiles([file]); MockFilePicker.afterOpenCallback = MockFilePicker.cleanup; |