tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

browser_sanitizeDialog_v2.js (26996B)


      1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /**
      8 * Tests the sanitize dialog (a.k.a. the clear recent history dialog).
      9 * See bug 480169.
     10 *
     11 * The purpose of this test is not to fully flex the sanitize timespan code;
     12 * browser/base/content/test/sanitize/browser_sanitize-timespans.js does that.  This
     13 * test checks the UI of the dialog and makes sure it's correctly connected to
     14 * the sanitize timespan code.
     15 *
     16 * Some of this code, especially the history creation parts, was taken from
     17 * browser/base/content/test/sanitize/browser_sanitize-timespans.js.
     18 */
     19 ChromeUtils.defineESModuleGetters(this, {
     20  PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs",
     21  Timer: "resource://gre/modules/Timer.sys.mjs",
     22  PermissionTestUtils: "resource://testing-common/PermissionTestUtils.sys.mjs",
     23  Downloads: "resource://gre/modules/Downloads.sys.mjs",
     24 });
     25 
     26 /**
     27 * Ensures that the specified URIs are either cleared or not.
     28 *
     29 * @param aURIs
     30 *        Array of page URIs
     31 * @param aShouldBeCleared
     32 *        True if each visit to the URI should be cleared, false otherwise
     33 */
     34 async function promiseHistoryClearedState(aURIs, aShouldBeCleared) {
     35  for (let uri of aURIs) {
     36    let visited = await PlacesUtils.history.hasVisits(uri);
     37    Assert.equal(
     38      visited,
     39      !aShouldBeCleared,
     40      `history visit ${uri.spec} should ${
     41        aShouldBeCleared ? "no longer" : "still"
     42      } exist`
     43    );
     44  }
     45 }
     46 
     47 /**
     48 * Ensures that the given pref is the expected value.
     49 *
     50 * @param {string} aPrefName
     51 *        The pref's sub-branch under the privacy branch
     52 * @param {boolean} aExpectedVal
     53 *        The pref's expected value
     54 * @param {string} aMsg
     55 *        Passed to is()
     56 */
     57 function boolPrefIs(aPrefName, aExpectedVal, aMsg) {
     58  is(Services.prefs.getBoolPref("privacy." + aPrefName), aExpectedVal, aMsg);
     59 }
     60 
     61 /**
     62 * Checks to see if the download with the specified path exists.
     63 *
     64 * @param  aPath
     65 *         The path of the download to check
     66 * @return True if the download exists, false otherwise
     67 */
     68 async function downloadExists(aPath) {
     69  let publicList = await Downloads.getList(Downloads.PUBLIC);
     70  let listArray = await publicList.getAll();
     71  return listArray.some(i => i.target.path == aPath);
     72 }
     73 
     74 /**
     75 * Ensures that the specified downloads are either cleared or not.
     76 *
     77 * @param aDownloadIDs
     78 *        Array of download database IDs
     79 * @param aShouldBeCleared
     80 *        True if each download should be cleared, false otherwise
     81 */
     82 async function ensureDownloadsClearedState(aDownloadIDs, aShouldBeCleared) {
     83  let niceStr = aShouldBeCleared ? "no longer" : "still";
     84  for (let id of aDownloadIDs) {
     85    is(
     86      await downloadExists(id),
     87      !aShouldBeCleared,
     88      "download " + id + " should " + niceStr + " exist"
     89    );
     90  }
     91 }
     92 
     93 /**
     94 * Checks if a form entry exists.
     95 */
     96 async function formNameExists(name) {
     97  return !!(await FormHistory.count({ fieldname: name }));
     98 }
     99 
    100 /**
    101 * Adds a form entry to history.
    102 *
    103 * @param aMinutesAgo
    104 *        The entry will be added this many minutes ago
    105 */
    106 function promiseAddFormEntryWithMinutesAgo(aMinutesAgo) {
    107  let name = aMinutesAgo + "-minutes-ago";
    108 
    109  // Artifically age the entry to the proper vintage.
    110  let timestamp = nowUSec - aMinutesAgo * kUsecPerMin;
    111 
    112  return FormHistory.update({
    113    op: "add",
    114    fieldname: name,
    115    value: "dummy",
    116    firstUsed: timestamp,
    117  });
    118 }
    119 
    120 /**
    121 * Adds a download to history.
    122 *
    123 * @param aMinutesAgo
    124 *        The download will be downloaded this many minutes ago
    125 */
    126 async function addDownloadWithMinutesAgo(aExpectedPathList, aMinutesAgo) {
    127  let publicList = await Downloads.getList(Downloads.PUBLIC);
    128 
    129  let name = "fakefile-" + aMinutesAgo + "-minutes-ago";
    130  let download = await Downloads.createDownload({
    131    source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
    132    target: name,
    133  });
    134  download.startTime = new Date(nowMSec - aMinutesAgo * kMsecPerMin);
    135  download.canceled = true;
    136  publicList.add(download);
    137 
    138  ok(
    139    await downloadExists(name),
    140    "Sanity check: download " + name + " should exist after creating it"
    141  );
    142 
    143  aExpectedPathList.push(name);
    144 }
    145 
    146 add_setup(async function () {
    147  requestLongerTimeout(3);
    148  await blankSlate();
    149  registerCleanupFunction(async function () {
    150    await blankSlate();
    151    await PlacesTestUtils.promiseAsyncUpdates();
    152  });
    153  await SpecialPowers.pushPrefEnv({
    154    set: [["privacy.sanitize.useOldClearHistoryDialog", false]],
    155  });
    156 
    157  // open preferences to trigger an updateSites()
    158  await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
    159  BrowserTestUtils.removeTab(gBrowser.selectedTab);
    160 });
    161 
    162 /**
    163 * Ensures that the given pref is the expected value.
    164 *
    165 * @param aPrefName
    166 *        The pref's sub-branch under the privacy branch
    167 * @param aExpectedVal
    168 *        The pref's expected value
    169 * @param aMsg
    170 *        Passed to is()
    171 */
    172 function intPrefIs(aPrefName, aExpectedVal, aMsg) {
    173  is(Services.prefs.getIntPref("privacy." + aPrefName), aExpectedVal, aMsg);
    174 }
    175 
    176 /**
    177 * Creates a visit time.
    178 *
    179 * @param aMinutesAgo
    180 *        The visit will be visited this many minutes ago
    181 */
    182 function visitTimeForMinutesAgo(aMinutesAgo) {
    183  return nowUSec - aMinutesAgo * kUsecPerMin;
    184 }
    185 
    186 /**
    187 *
    188 * Opens dialog in the provided context and selects the checkboxes
    189 * as sent in the parameters
    190 *
    191 * @param {object} context the dialog is opened in, timespan to select,
    192 *  if browsingHistoryAndDownloads, cookiesAndStorage, cache or siteSettings
    193 *  are checked
    194 */
    195 async function performActionsOnDialog({
    196  context = "browser",
    197  timespan = Sanitizer.TIMESPAN_HOUR,
    198  browsingHistoryAndDownloads = true,
    199  cookiesAndStorage = true,
    200  cache = false,
    201  siteSettings = false,
    202  formData = false,
    203 }) {
    204  let dh = new ClearHistoryDialogHelper({ mode: context });
    205  dh.onload = function () {
    206    this.selectDuration(timespan);
    207    this.checkPrefCheckbox(
    208      "browsingHistoryAndDownloads",
    209      browsingHistoryAndDownloads
    210    );
    211    this.checkPrefCheckbox("cookiesAndStorage", cookiesAndStorage);
    212    this.checkPrefCheckbox("cache", cache);
    213    this.checkPrefCheckbox("siteSettings", siteSettings);
    214    this.checkPrefCheckbox("formdata", formData);
    215    this.acceptDialog();
    216  };
    217  dh.open();
    218  await dh.promiseClosed;
    219 }
    220 
    221 /**
    222 * Initializes the dialog to its default state.
    223 */
    224 add_task(async function default_state() {
    225  let dh = new ClearHistoryDialogHelper();
    226  dh.onload = function () {
    227    // Select "Last Hour"
    228    this.selectDuration(Sanitizer.TIMESPAN_HOUR);
    229    this.acceptDialog();
    230  };
    231  dh.open();
    232  await dh.promiseClosed;
    233 });
    234 
    235 /**
    236 * Cancels the dialog, makes sure history not cleared.
    237 */
    238 add_task(async function test_cancel() {
    239  // Add history (within the past hour)
    240  let uris = [];
    241  let places = [];
    242  let pURI;
    243  for (let i = 0; i < 30; i++) {
    244    pURI = makeURI("https://" + i + "-minutes-ago.com/");
    245    places.push({ uri: pURI, visitDate: visitTimeForMinutesAgo(i) });
    246    uris.push(pURI);
    247  }
    248  await PlacesTestUtils.addVisits(places);
    249 
    250  let dh = new ClearHistoryDialogHelper();
    251  dh.onload = function () {
    252    this.selectDuration(Sanitizer.TIMESPAN_HOUR);
    253    this.checkPrefCheckbox("browsingHistoryAndDownloads", false);
    254    this.cancelDialog();
    255  };
    256  dh.onunload = async function () {
    257    await promiseHistoryClearedState(uris, false);
    258    await blankSlate();
    259    await promiseHistoryClearedState(uris, true);
    260  };
    261  dh.open();
    262  await dh.promiseClosed;
    263 });
    264 
    265 // test remembering user options for various entry points
    266 add_task(async function test_pref_remembering() {
    267  let dh = new ClearHistoryDialogHelper({ mode: "clearSiteData" });
    268  dh.onload = function () {
    269    this.checkPrefCheckbox("cookiesAndStorage", false);
    270    this.checkPrefCheckbox("siteSettings", true);
    271 
    272    this.acceptDialog();
    273  };
    274  dh.open();
    275  await dh.promiseClosed;
    276 
    277  // validate if prefs are remembered
    278  dh = new ClearHistoryDialogHelper({ mode: "clearSiteData" });
    279  dh.onload = function () {
    280    this.validateCheckbox("cookiesAndStorage", false);
    281    this.validateCheckbox("siteSettings", true);
    282 
    283    this.checkPrefCheckbox("cookiesAndStorage", true);
    284    this.checkPrefCheckbox("siteSettings", false);
    285 
    286    // we will test cancelling the dialog, to make sure it doesn't remember
    287    // the prefs when cancelled
    288    this.cancelDialog();
    289  };
    290  dh.open();
    291  await dh.promiseClosed;
    292 
    293  // validate if prefs did not change since we cancelled the dialog
    294  dh = new ClearHistoryDialogHelper({ mode: "clearSiteData" });
    295  dh.onload = function () {
    296    this.validateCheckbox("cookiesAndStorage", false);
    297    this.validateCheckbox("siteSettings", true);
    298 
    299    this.cancelDialog();
    300  };
    301  dh.open();
    302  await dh.promiseClosed;
    303 
    304  if (!settingsRedesignHistoryEnabled()) {
    305    // test rememebering prefs from the clear history context
    306    // since clear history and clear site data have seperate remembering
    307    // of prefs
    308    dh = new ClearHistoryDialogHelper({ mode: "clearHistory" });
    309    dh.onload = function () {
    310      this.checkPrefCheckbox("cookiesAndStorage", true);
    311      this.checkPrefCheckbox("siteSettings", false);
    312      this.checkPrefCheckbox("cache", false);
    313 
    314      this.acceptDialog();
    315    };
    316    dh.open();
    317    await dh.promiseClosed;
    318  }
    319 
    320  // validate if prefs are remembered across both clear history and browser
    321  dh = new ClearHistoryDialogHelper({ mode: "browser" });
    322  dh.onload = function () {
    323    this.validateCheckbox("cookiesAndStorage", true);
    324    this.validateCheckbox("siteSettings", false);
    325    if (!settingsRedesignHistoryEnabled()) {
    326      this.validateCheckbox("cache", false);
    327    }
    328 
    329    this.cancelDialog();
    330  };
    331  dh.open();
    332  await dh.promiseClosed;
    333 });
    334 
    335 /**
    336 * Ensures that the "Everything" duration option works.
    337 */
    338 add_task(async function test_everything() {
    339  // Add history.
    340  let uris = [];
    341  let places = [];
    342  let pURI;
    343  // within past hour, within past two hours, within past four hours and
    344  // outside past four hours
    345  [10, 70, 130, 250].forEach(function (aValue) {
    346    pURI = makeURI("https://" + aValue + "-minutes-ago.com/");
    347    places.push({ uri: pURI, visitDate: visitTimeForMinutesAgo(aValue) });
    348    uris.push(pURI);
    349  });
    350 
    351  let promiseSanitized = promiseSanitizationComplete();
    352 
    353  await PlacesTestUtils.addVisits(places);
    354  let dh = new ClearHistoryDialogHelper();
    355  dh.onload = function () {
    356    is(
    357      this.isWarningPanelVisible(),
    358      false,
    359      "Warning panel should be hidden after previously accepting dialog " +
    360        "with a predefined timespan"
    361    );
    362    this.selectDuration(Sanitizer.TIMESPAN_EVERYTHING);
    363    this.checkPrefCheckbox("browsingHistoryAndDownloads", true);
    364    this.acceptDialog();
    365  };
    366  dh.onunload = async function () {
    367    await promiseSanitized;
    368    intPrefIs(
    369      "sanitize.timeSpan",
    370      Sanitizer.TIMESPAN_EVERYTHING,
    371      "timeSpan pref should be everything after accepting dialog " +
    372        "with everything selected"
    373    );
    374 
    375    await promiseHistoryClearedState(uris, true);
    376  };
    377  dh.open();
    378  await dh.promiseClosed;
    379 });
    380 
    381 /**
    382 * Ensures that the "Everything" warning is visible on dialog open after
    383 * the previous test.
    384 */
    385 add_task(async function test_everything_warning() {
    386  // Add history.
    387  let uris = [];
    388  let places = [];
    389  let pURI;
    390  // within past hour, within past two hours, within past four hours and
    391  // outside past four hours
    392  [10, 70, 130, 250].forEach(function (aValue) {
    393    pURI = makeURI("https://" + aValue + "-minutes-ago.com/");
    394    places.push({ uri: pURI, visitDate: visitTimeForMinutesAgo(aValue) });
    395    uris.push(pURI);
    396  });
    397 
    398  let promiseSanitized = promiseSanitizationComplete();
    399 
    400  await PlacesTestUtils.addVisits(places);
    401  let dh = new ClearHistoryDialogHelper();
    402  dh.onload = function () {
    403    is(
    404      this.isWarningPanelVisible(),
    405      true,
    406      "Warning panel should be visible after previously accepting dialog " +
    407        "with clearing everything"
    408    );
    409    this.selectDuration(Sanitizer.TIMESPAN_EVERYTHING);
    410    this.checkPrefCheckbox("browsingHistoryAndDownloads", true);
    411    this.acceptDialog();
    412  };
    413  dh.onunload = async function () {
    414    intPrefIs(
    415      "sanitize.timeSpan",
    416      Sanitizer.TIMESPAN_EVERYTHING,
    417      "timeSpan pref should be everything after accepting dialog " +
    418        "with everything selected"
    419    );
    420 
    421    await promiseSanitized;
    422 
    423    await promiseHistoryClearedState(uris, true);
    424  };
    425  dh.open();
    426  await dh.promiseClosed;
    427 });
    428 
    429 /**
    430 * Tests that the clearing button gets disabled if no checkboxes are checked
    431 * and enabled when at least one checkbox is checked
    432 */
    433 add_task(async function testAcceptButtonDisabled() {
    434  let dh = new ClearHistoryDialogHelper();
    435  dh.onload = async function () {
    436    let clearButton = this.win.document
    437      .querySelector("dialog")
    438      .getButton("accept");
    439    this.uncheckAllCheckboxes();
    440    await new Promise(resolve => SimpleTest.executeSoon(resolve));
    441    is(clearButton.disabled, true, "Clear button should be disabled");
    442 
    443    this.checkPrefCheckbox("cache", true);
    444    await new Promise(resolve => SimpleTest.executeSoon(resolve));
    445    is(clearButton.disabled, false, "Clear button should not be disabled");
    446 
    447    this.cancelDialog();
    448  };
    449  dh.open();
    450  await dh.promiseClosed;
    451 });
    452 
    453 /**
    454 * Tests to see if the warning box is hidden when opened in the clear on shutdown context
    455 */
    456 add_task(async function testWarningBoxInClearOnShutdown() {
    457  let dh = new ClearHistoryDialogHelper({ mode: "clearSiteData" });
    458  dh.onload = function () {
    459    this.selectDuration(Sanitizer.TIMESPAN_EVERYTHING);
    460    is(
    461      BrowserTestUtils.isVisible(this.getWarningPanel()),
    462      true,
    463      `warning panel should be visible`
    464    );
    465    this.acceptDialog();
    466  };
    467  dh.open();
    468  await dh.promiseClosed;
    469 
    470  dh = new ClearHistoryDialogHelper({ mode: "clearOnShutdown" });
    471  dh.onload = function () {
    472    is(
    473      BrowserTestUtils.isVisible(this.getWarningPanel()),
    474      false,
    475      `warning panel should not be visible`
    476    );
    477 
    478    this.cancelDialog();
    479  };
    480  dh.open();
    481  await dh.promiseClosed;
    482 });
    483 
    484 /**
    485 * Checks if clearing history and downloads for the simple timespan
    486 * behaves as expected
    487 */
    488 add_task(async function test_history_downloads_checked() {
    489  // Add downloads (within the past hour).
    490  let downloadIDs = [];
    491  for (let i = 0; i < 5; i++) {
    492    await addDownloadWithMinutesAgo(downloadIDs, i);
    493  }
    494  // Add downloads (over an hour ago).
    495  let olderDownloadIDs = [];
    496  for (let i = 0; i < 5; i++) {
    497    await addDownloadWithMinutesAgo(olderDownloadIDs, 61 + i);
    498  }
    499 
    500  // Add history (within the past hour).
    501  let uris = [];
    502  let places = [];
    503  let pURI;
    504  for (let i = 0; i < 30; i++) {
    505    pURI = makeURI("https://" + i + "-minutes-ago.com/");
    506    places.push({ uri: pURI, visitDate: visitTimeForMinutesAgo(i) });
    507    uris.push(pURI);
    508  }
    509  // Add history (over an hour ago).
    510  let olderURIs = [];
    511  for (let i = 0; i < 5; i++) {
    512    pURI = makeURI("https://" + (61 + i) + "-minutes-ago.com/");
    513    places.push({ uri: pURI, visitDate: visitTimeForMinutesAgo(61 + i) });
    514    olderURIs.push(pURI);
    515  }
    516  let promiseSanitized = promiseSanitizationComplete();
    517 
    518  await PlacesTestUtils.addVisits(places);
    519 
    520  let dh = new ClearHistoryDialogHelper();
    521  dh.onload = function () {
    522    this.selectDuration(Sanitizer.TIMESPAN_HOUR);
    523    this.checkPrefCheckbox("browsingHistoryAndDownloads", true);
    524    this.acceptDialog();
    525  };
    526  dh.onunload = async function () {
    527    intPrefIs(
    528      "sanitize.timeSpan",
    529      Sanitizer.TIMESPAN_HOUR,
    530      "timeSpan pref should be hour after accepting dialog with " +
    531        "hour selected"
    532    );
    533 
    534    await promiseSanitized;
    535 
    536    // History visits and downloads within one hour should be cleared.
    537    await promiseHistoryClearedState(uris, true);
    538    await ensureDownloadsClearedState(downloadIDs, true);
    539 
    540    // Visits and downloads > 1 hour should still exist.
    541    await promiseHistoryClearedState(olderURIs, false);
    542    await ensureDownloadsClearedState(olderDownloadIDs, false);
    543 
    544    // OK, done, cleanup after ourselves.
    545    await blankSlate();
    546    await promiseHistoryClearedState(olderURIs, true);
    547    await ensureDownloadsClearedState(olderDownloadIDs, true);
    548  };
    549  dh.open();
    550  await dh.promiseClosed;
    551 });
    552 
    553 /**
    554 * The next three tests checks that when a certain history item cannot be
    555 * cleared then the checkbox should be both disabled and unchecked.
    556 * In addition, we ensure that this behavior does not modify the preferences.
    557 */
    558 add_task(async function test_cannot_clear_history() {
    559  // Add form entries
    560  let formEntries = [await promiseAddFormEntryWithMinutesAgo(10)];
    561 
    562  let promiseSanitized = promiseSanitizationComplete();
    563 
    564  // Add history.
    565  let pURI = makeURI("https://" + 10 + "-minutes-ago.com/");
    566  await PlacesTestUtils.addVisits({
    567    uri: pURI,
    568    visitDate: visitTimeForMinutesAgo(10),
    569  });
    570  let uris = [pURI];
    571 
    572  let dh = new ClearHistoryDialogHelper();
    573  dh.onload = function () {
    574    var cb = this.win.document.querySelectorAll(
    575      "checkbox[id='browsingHistoryAndDownloads']"
    576    );
    577    ok(
    578      cb.length == 1 && !cb[0].disabled,
    579      "There is history, checkbox to clear history should be enabled."
    580    );
    581 
    582    this.checkPrefCheckbox("formdata", true);
    583    this.checkPrefCheckbox("browsingHistoryAndDownloads", true);
    584    this.acceptDialog();
    585  };
    586  dh.onunload = async function () {
    587    await promiseSanitized;
    588 
    589    await promiseHistoryClearedState(uris, true);
    590 
    591    let exists = await formNameExists(formEntries[0]);
    592    ok(!exists, "form entry " + formEntries[0] + " should no longer exist");
    593  };
    594  dh.open();
    595  await dh.promiseClosed;
    596 });
    597 
    598 add_task(async function test_no_history_to_clear() {
    599  let promiseSanitized = promiseSanitizationComplete();
    600  let dh = new ClearHistoryDialogHelper();
    601  dh.onload = function () {
    602    var cb = this.win.document.querySelectorAll(
    603      "checkbox[id='browsingHistoryAndDownloads']"
    604    );
    605    ok(
    606      cb.length == 1 && !cb[0].disabled && cb[0].checked,
    607      "There is no history, but history checkbox should always be enabled " +
    608        "and will be checked from previous preference."
    609    );
    610 
    611    this.acceptDialog();
    612  };
    613  dh.open();
    614  await dh.promiseClosed;
    615  await promiseSanitized;
    616 });
    617 
    618 add_task(async function test_form_entries() {
    619  let formEntry = await promiseAddFormEntryWithMinutesAgo(10);
    620 
    621  let promiseSanitized = promiseSanitizationComplete();
    622 
    623  let dh = new ClearHistoryDialogHelper();
    624  dh.onload = function () {
    625    var cb = this.win.document.querySelectorAll("checkbox[id='formdata']");
    626    is(cb.length, 1, "There is only one checkbox for form data");
    627    ok(!cb[0].disabled, "The checkbox is enabled");
    628    ok(cb[0].checked, "The checkbox is checked");
    629 
    630    this.acceptDialog();
    631  };
    632  dh.onunload = async function () {
    633    await promiseSanitized;
    634    let exists = await formNameExists(formEntry);
    635    ok(!exists, "form entry " + formEntry + " should no longer exist");
    636  };
    637  dh.open();
    638  await dh.promiseClosed;
    639 });
    640 
    641 // test the case when we open the dialog through the clear on shutdown settings
    642 add_task(async function test_clear_on_shutdown() {
    643  await SpecialPowers.pushPrefEnv({
    644    set: [["privacy.sanitize.sanitizeOnShutdown", true]],
    645  });
    646 
    647  let dh = new ClearHistoryDialogHelper({ mode: "clearOnShutdown" });
    648  dh.onload = async function () {
    649    this.uncheckAllCheckboxes();
    650    this.checkPrefCheckbox("browsingHistoryAndDownloads", false);
    651    this.checkPrefCheckbox("cookiesAndStorage", true);
    652    this.acceptDialog();
    653  };
    654  dh.open();
    655  await dh.promiseClosed;
    656 
    657  // Add downloads (within the past hour).
    658  let downloadIDs = [];
    659  for (let i = 0; i < 5; i++) {
    660    await addDownloadWithMinutesAgo(downloadIDs, i);
    661  }
    662  // Add downloads (over an hour ago).
    663  let olderDownloadIDs = [];
    664  for (let i = 0; i < 5; i++) {
    665    await addDownloadWithMinutesAgo(olderDownloadIDs, 61 + i);
    666  }
    667 
    668  boolPrefIs(
    669    "clearOnShutdown_v2.browsingHistoryAndDownloads",
    670    false,
    671    "clearOnShutdown_v2 history should be false"
    672  );
    673 
    674  boolPrefIs(
    675    "clearOnShutdown_v2.cookiesAndStorage",
    676    true,
    677    "clearOnShutdown_v2 cookies should be true"
    678  );
    679 
    680  boolPrefIs(
    681    "clearOnShutdown_v2.cache",
    682    false,
    683    "clearOnShutdown_v2 cache should be false"
    684  );
    685 
    686  await createDummyDataForHost("example.org");
    687  await createDummyDataForHost("example.com");
    688 
    689  ok(
    690    await SiteDataTestUtils.hasIndexedDB("https://example.org"),
    691    "We have indexedDB data for example.org"
    692  );
    693  ok(
    694    await SiteDataTestUtils.hasIndexedDB("https://example.com"),
    695    "We have indexedDB data for example.com"
    696  );
    697 
    698  // Cleaning up
    699  await Sanitizer.runSanitizeOnShutdown();
    700 
    701  // Data for example.org should be cleared
    702  ok(
    703    !(await SiteDataTestUtils.hasIndexedDB("https://example.org")),
    704    "We don't have indexedDB data for example.org"
    705  );
    706  // Data for example.com should be cleared
    707  ok(
    708    !(await SiteDataTestUtils.hasIndexedDB("https://example.com")),
    709    "We don't have indexedDB data for example.com"
    710  );
    711 
    712  // Downloads shouldn't have cleared
    713  await ensureDownloadsClearedState(downloadIDs, false);
    714  await ensureDownloadsClearedState(olderDownloadIDs, false);
    715 
    716  dh = new ClearHistoryDialogHelper({ mode: "clearOnShutdown" });
    717  dh.onload = async function () {
    718    this.uncheckAllCheckboxes();
    719    this.checkPrefCheckbox("browsingHistoryAndDownloads", true);
    720    this.acceptDialog();
    721  };
    722  dh.open();
    723  await dh.promiseClosed;
    724 
    725  boolPrefIs(
    726    "clearOnShutdown_v2.browsingHistoryAndDownloads",
    727    true,
    728    "clearOnShutdown_v2 history should be true"
    729  );
    730 
    731  boolPrefIs(
    732    "clearOnShutdown_v2.cookiesAndStorage",
    733    false,
    734    "clearOnShutdown_v2 cookies should be false"
    735  );
    736 
    737  boolPrefIs(
    738    "clearOnShutdown_v2.cache",
    739    false,
    740    "clearOnShutdown_v2 cache should be false"
    741  );
    742 
    743  ok(
    744    await SiteDataTestUtils.hasIndexedDB("https://example.org"),
    745    "We have indexedDB data for example.org"
    746  );
    747  ok(
    748    await SiteDataTestUtils.hasIndexedDB("https://example.com"),
    749    "We have indexedDB data for example.com"
    750  );
    751 
    752  // Cleaning up
    753  await Sanitizer.runSanitizeOnShutdown();
    754 
    755  // Data for example.org should not be cleared
    756  ok(
    757    await SiteDataTestUtils.hasIndexedDB("https://example.org"),
    758    "We have indexedDB data for example.org"
    759  );
    760  // Data for example.com should not be cleared
    761  ok(
    762    await SiteDataTestUtils.hasIndexedDB("https://example.com"),
    763    "We have indexedDB data for example.com"
    764  );
    765 
    766  // downloads should have cleared
    767  await ensureDownloadsClearedState(downloadIDs, true);
    768  await ensureDownloadsClearedState(olderDownloadIDs, true);
    769 
    770  // Clean up
    771  await SiteDataTestUtils.clear();
    772 });
    773 
    774 if (!settingsRedesignHistoryEnabled()) {
    775  add_task(async function testClearHistoryCheckboxStatesAfterMigration() {
    776    await SpecialPowers.pushPrefEnv({
    777      set: [
    778        ["privacy.cpd.history", false],
    779        ["privacy.cpd.formdata", true],
    780        ["privacy.cpd.cookies", true],
    781        ["privacy.cpd.offlineApps", false],
    782        ["privacy.cpd.sessions", false],
    783        ["privacy.cpd.siteSettings", false],
    784        ["privacy.cpd.cache", true],
    785        // Set cookiesAndStorage to verify that the pref is flipped in the test
    786        ["privacy.clearHistory.cookiesAndStorage", false],
    787        // We set the old migrate pref to false to simulate a user who has not migrated to the new dialog.
    788        // we should follow the user's old prefs with "cpd." prefix in this case.
    789        ["privacy.sanitize.cpd.hasMigratedToNewPrefs2", false],
    790        ["privacy.sanitize.cpd.hasMigratedToNewPrefs3", false],
    791      ],
    792    });
    793 
    794    let dh = new ClearHistoryDialogHelper({ mode: "clearHistory" });
    795    dh.onload = function () {
    796      this.validateCheckbox("cookiesAndStorage", true);
    797      this.validateCheckbox("browsingHistoryAndDownloads", false);
    798      this.validateCheckbox("formdata", true);
    799      this.validateCheckbox("cache", true);
    800      this.validateCheckbox("siteSettings", false);
    801 
    802      this.checkPrefCheckbox("siteSettings", true);
    803      this.checkPrefCheckbox("cookiesAndStorage", false);
    804      this.acceptDialog();
    805    };
    806    dh.open();
    807    await dh.promiseClosed;
    808 
    809    is(
    810      Services.prefs.getBoolPref("privacy.sanitize.cpd.hasMigratedToNewPrefs3"),
    811      true,
    812      "Migration is complete for cpd branch"
    813    );
    814 
    815    // make sure the migration doesn't run again
    816    dh = new ClearHistoryDialogHelper({ mode: "clearHistory" });
    817    dh.onload = function () {
    818      this.validateCheckbox("siteSettings", true);
    819      this.validateCheckbox("cookiesAndStorage", false);
    820      this.cancelDialog();
    821    };
    822    dh.open();
    823    await dh.promiseClosed;
    824  });
    825 
    826  add_task(async function testClearHistoryCheckboxStatesAfterMigration3() {
    827    await SpecialPowers.pushPrefEnv({
    828      set: [
    829        ["privacy.cpd.history", false],
    830        ["privacy.cpd.formdata", true],
    831        ["privacy.cpd.cookies", true],
    832        ["privacy.cpd.offlineApps", false],
    833        ["privacy.cpd.sessions", false],
    834        ["privacy.cpd.siteSettings", true],
    835        ["privacy.cpd.cache", true],
    836        // Verify that prefs not in not touched in migration from v2
    837        ["privacy.clearHistory.cookiesAndStorage", false],
    838        ["privacy.clearHistory.siteSettings", false],
    839        ["privacy.clearHistory.cache", false],
    840        // Verify that formData and browsingHistoryAndDownloads inherit this value
    841        ["privacy.clearHistory.historyFormDataAndDownloads", true],
    842        // migrate from v2 to v3, dont redo the v1 to v2 migration
    843        ["privacy.sanitize.cpd.hasMigratedToNewPrefs2", true],
    844        ["privacy.sanitize.cpd.hasMigratedToNewPrefs3", false],
    845      ],
    846    });
    847 
    848    let dh = new ClearHistoryDialogHelper({ mode: "clearHistory" });
    849    dh.onload = function () {
    850      // migration to v3 shouldn't modify these values
    851      this.validateCheckbox("cookiesAndStorage", false);
    852      this.validateCheckbox("siteSettings", false);
    853      this.validateCheckbox("cache", false);
    854 
    855      // migration to v3 should set them initially to true from historyFormDataAndDownloads pref
    856      this.validateCheckbox("browsingHistoryAndDownloads", true);
    857      this.validateCheckbox("formdata", true);
    858 
    859      // flip two prefs to open to verify migration doesn't happen again and checkboxes retain their value
    860      this.checkPrefCheckbox("siteSettings", true);
    861      this.checkPrefCheckbox("browsingHistoryAndDownloads", false);
    862      this.acceptDialog();
    863    };
    864    dh.open();
    865    await dh.promiseClosed;
    866 
    867    is(
    868      Services.prefs.getBoolPref("privacy.sanitize.cpd.hasMigratedToNewPrefs3"),
    869      true,
    870      "Migration is complete for cpd branch"
    871    );
    872 
    873    // make sure the migration doesn't run again
    874    dh = new ClearHistoryDialogHelper({ mode: "clearHistory" });
    875    dh.onload = function () {
    876      this.validateCheckbox("siteSettings", true);
    877      this.validateCheckbox("browsingHistoryAndDownloads", false);
    878      this.cancelDialog();
    879    };
    880    dh.open();
    881    await dh.promiseClosed;
    882  });
    883 }