diff options
Diffstat (limited to 'browser/base/content/test/sanitize')
7 files changed, 802 insertions, 638 deletions
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" + ); + } + }, +}; |