tor-browser

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

browser_protectionsUI.js (20240B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 /* Basic UI tests for the protections panel */
      5 
      6 "use strict";
      7 
      8 const TRACKING_PAGE =
      9  // eslint-disable-next-line @microsoft/sdl/no-insecure-url
     10  "http://tracking.example.org/browser/browser/base/content/test/protectionsUI/trackingPage.html";
     11 
     12 ChromeUtils.defineESModuleGetters(this, {
     13  ContentBlockingAllowList:
     14    "resource://gre/modules/ContentBlockingAllowList.sys.mjs",
     15 });
     16 
     17 const { CustomizableUITestUtils } = ChromeUtils.importESModule(
     18  "resource://testing-common/CustomizableUITestUtils.sys.mjs"
     19 );
     20 
     21 requestLongerTimeout(3);
     22 
     23 add_setup(async function () {
     24  await SpecialPowers.pushPrefEnv({
     25    set: [
     26      // Set the auto hide timing to 100ms for blocking the test less.
     27      ["browser.protections_panel.toast.timeout", 100],
     28      // Hide protections cards so as not to trigger more async messaging
     29      // when landing on the page.
     30      ["browser.contentblocking.report.monitor.enabled", false],
     31      ["browser.contentblocking.report.lockwise.enabled", false],
     32      ["browser.contentblocking.report.proxy.enabled", false],
     33      ["privacy.trackingprotection.enabled", true],
     34      ["browser.urlbar.scotchBonnet.enableOverride", true],
     35    ],
     36  });
     37 
     38  let oldCanRecord = Services.telemetry.canRecordExtended;
     39  Services.telemetry.canRecordExtended = true;
     40  Services.telemetry.clearEvents();
     41 
     42  registerCleanupFunction(() => {
     43    Services.telemetry.canRecordExtended = oldCanRecord;
     44    Services.telemetry.clearEvents();
     45  });
     46 
     47  Services.fog.testResetFOG();
     48 });
     49 
     50 async function clickToggle(toggle) {
     51  let changed = BrowserTestUtils.waitForEvent(toggle, "toggle");
     52  await EventUtils.synthesizeMouseAtCenter(toggle.buttonEl, {});
     53  await changed;
     54 }
     55 
     56 add_task(async function testToggleSwitch() {
     57  let tab = await BrowserTestUtils.openNewForegroundTab(
     58    gBrowser,
     59    TRACKING_PAGE
     60  );
     61 
     62  await openProtectionsPanel();
     63 
     64  await TestUtils.waitForCondition(() => {
     65    return gProtectionsHandler._protectionsPopup.hasAttribute("blocking");
     66  });
     67 
     68  let buttonEvents =
     69    Glean.securityUiProtectionspopup.openProtectionsPopup.testGetValue();
     70 
     71  is(buttonEvents.length, 1, "recorded telemetry for opening the popup");
     72 
     73  let browserLoadedPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
     74 
     75  let popuphiddenPromise = BrowserTestUtils.waitForEvent(
     76    gProtectionsHandler._protectionsPopup,
     77    "popuphidden"
     78  );
     79 
     80  await clickToggle(gProtectionsHandler._protectionsPopupTPSwitch);
     81  await popuphiddenPromise;
     82 
     83  checkClickTelemetry("etp_toggle_off");
     84 
     85  // We need to wait toast's popup shown and popup hidden events. It won't fire
     86  // the popup shown event if we open the protections panel while the toast is
     87  // opening.
     88  let toastShown = waitForProtectionsPanelToast();
     89 
     90  await browserLoadedPromise;
     91 
     92  // Wait until the ETP state confirmation toast is shown and hides itself.
     93  await toastShown;
     94 
     95  // Re-open the protections panel and confirm that the toggle is off, then toggle it back on.
     96  await openProtectionsPanel();
     97  ok(
     98    !gProtectionsHandler._protectionsPopupTPSwitch.hasAttribute("pressed"),
     99    "TP Switch should be off"
    100  );
    101 
    102  browserLoadedPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
    103 
    104  popuphiddenPromise = BrowserTestUtils.waitForEvent(
    105    gProtectionsHandler._protectionsPopup,
    106    "popuphidden"
    107  );
    108 
    109  await clickToggle(gProtectionsHandler._protectionsPopupTPSwitch);
    110 
    111  // Wait for the protections panel to be hidden as the result of the ETP toggle
    112  // on action.
    113  await popuphiddenPromise;
    114 
    115  toastShown = waitForProtectionsPanelToast();
    116 
    117  await browserLoadedPromise;
    118 
    119  // Wait until the ETP state confirmation toast is shown and hides itself.
    120  await toastShown;
    121 
    122  checkClickTelemetry("etp_toggle_on");
    123 
    124  ContentBlockingAllowList.remove(tab.linkedBrowser);
    125  BrowserTestUtils.removeTab(tab);
    126 });
    127 
    128 /**
    129 * A test for the protection settings button.
    130 */
    131 add_task(async function testSettingsButton() {
    132  // Open a tab and its protection panel.
    133  let tab = await BrowserTestUtils.openNewForegroundTab(
    134    gBrowser,
    135    "https://example.com"
    136  );
    137  await openProtectionsPanel();
    138 
    139  let popuphiddenPromise = BrowserTestUtils.waitForEvent(
    140    gProtectionsHandler._protectionsPopup,
    141    "popuphidden"
    142  );
    143  let newTabPromise = BrowserTestUtils.waitForNewTab(
    144    gBrowser,
    145    "about:preferences#privacy"
    146  );
    147  gProtectionsHandler._protectionsPopupSettingsButton.click();
    148 
    149  // The protection popup should be hidden after clicking settings button.
    150  await popuphiddenPromise;
    151  // Wait until the about:preferences has been opened correctly.
    152  let newTab = await newTabPromise;
    153 
    154  ok(true, "about:preferences has been opened successfully");
    155  checkClickTelemetry("settings");
    156 
    157  BrowserTestUtils.removeTab(newTab);
    158  BrowserTestUtils.removeTab(tab);
    159 });
    160 
    161 /**
    162 * A test for ensuring Tracking Protection label is shown correctly
    163 */
    164 add_task(async function testTrackingProtectionLabel() {
    165  // Open a tab.
    166  let tab = await BrowserTestUtils.openNewForegroundTab(
    167    gBrowser,
    168    "https://example.com"
    169  );
    170  await openProtectionsPanel();
    171 
    172  let trackingProtectionLabel = document.getElementById(
    173    "protections-popup-footer-protection-type-label"
    174  );
    175 
    176  is(
    177    trackingProtectionLabel.textContent,
    178    "Custom",
    179    "The label is correctly set to Custom."
    180  );
    181  await closeProtectionsPanel();
    182 
    183  Services.prefs.setStringPref("browser.contentblocking.category", "standard");
    184  await openProtectionsPanel();
    185 
    186  is(
    187    trackingProtectionLabel.textContent,
    188    "Standard",
    189    "The label is correctly set to Standard."
    190  );
    191  await closeProtectionsPanel();
    192 
    193  Services.prefs.setStringPref("browser.contentblocking.category", "strict");
    194  await openProtectionsPanel();
    195 
    196  is(
    197    trackingProtectionLabel.textContent,
    198    "Strict",
    199    "The label is correctly set to Strict."
    200  );
    201 
    202  await closeProtectionsPanel();
    203  Services.prefs.setStringPref("browser.contentblocking.category", "custom");
    204  BrowserTestUtils.removeTab(tab);
    205 });
    206 
    207 /**
    208 * A test for the 'Show Full Report' button in the footer section.
    209 */
    210 add_task(async function testShowFullReportButton() {
    211  // Open a tab and its protection panel.
    212  let tab = await BrowserTestUtils.openNewForegroundTab(
    213    gBrowser,
    214    "https://example.com"
    215  );
    216  await openProtectionsPanel();
    217 
    218  let popuphiddenPromise = BrowserTestUtils.waitForEvent(
    219    gProtectionsHandler._protectionsPopup,
    220    "popuphidden"
    221  );
    222  let newTabPromise = waitForAboutProtectionsTab();
    223  let showFullReportButton = document.getElementById(
    224    "protections-popup-show-report-button"
    225  );
    226 
    227  showFullReportButton.click();
    228 
    229  // The protection popup should be hidden after clicking the link.
    230  await popuphiddenPromise;
    231  // Wait until the 'about:protections' has been opened correctly.
    232  let newTab = await newTabPromise;
    233 
    234  ok(true, "about:protections has been opened successfully");
    235 
    236  checkClickTelemetry("full_report");
    237 
    238  BrowserTestUtils.removeTab(newTab);
    239  BrowserTestUtils.removeTab(tab);
    240 });
    241 
    242 function checkMiniPanel() {
    243  // Check that only the header is displayed.
    244  let mainView = document.getElementById("protections-popup-mainView");
    245  for (let item of mainView.childNodes) {
    246    if (item.id !== "protections-popup-mainView-panel-header-section") {
    247      ok(
    248        !BrowserTestUtils.isVisible(item),
    249        `The section '${item.id}' is hidden in the toast.`
    250      );
    251    } else {
    252      ok(
    253        BrowserTestUtils.isVisible(item),
    254        "The panel header is displayed as the content of the toast."
    255      );
    256    }
    257  }
    258 }
    259 
    260 /**
    261 * A test for ensuring the mini panel closes automatically
    262 */
    263 add_task(async function testMiniPanel() {
    264  // Open a tab.
    265  let tab = await BrowserTestUtils.openNewForegroundTab(
    266    gBrowser,
    267    "https://example.com"
    268  );
    269 
    270  // Open the mini panel.
    271  await openProtectionsPanel(true);
    272  let popuphiddenPromise = BrowserTestUtils.waitForEvent(
    273    gProtectionsHandler._protectionsPopup,
    274    "popuphidden"
    275  );
    276 
    277  checkMiniPanel();
    278 
    279  // Wait until the auto hide is happening.
    280  await popuphiddenPromise;
    281 
    282  ok(true, "The mini panel hides automatically.");
    283 
    284  BrowserTestUtils.removeTab(tab);
    285 });
    286 
    287 /**
    288 * A test for ensuring that clicking the mini panel opens the big panel
    289 */
    290 add_task(async function testMiniPanelClick() {
    291  // Open a tab.
    292  let tab = await BrowserTestUtils.openNewForegroundTab(
    293    gBrowser,
    294    "https://example.com"
    295  );
    296 
    297  // Open the mini panel.
    298  await openProtectionsPanel(true);
    299  let popuphiddenPromise = BrowserTestUtils.waitForEvent(
    300    gProtectionsHandler._protectionsPopup,
    301    "popuphidden"
    302  );
    303 
    304  checkMiniPanel();
    305 
    306  let popupShownPromise = BrowserTestUtils.waitForEvent(
    307    window,
    308    "popupshown",
    309    true,
    310    e => e.target.id == "protections-popup"
    311  );
    312 
    313  // Simulate clicking on the mini panel text
    314  let buttonEl = document.getElementById(
    315    "protections-popup-toast-panel-tp-on-desc"
    316  );
    317  await EventUtils.synthesizeMouseAtCenter(buttonEl, {});
    318 
    319  info("Waiting for mini panel to close");
    320  await popuphiddenPromise;
    321 
    322  info("Waiting for big popup to be shown");
    323  await popupShownPromise;
    324 
    325  let header = document.getElementById(
    326    "protections-popup-mainView-panel-header-section"
    327  );
    328  ok(BrowserTestUtils.isVisible(header), "Header is visible");
    329 
    330  let body = document.getElementById("protections-popup-main-body");
    331  ok(BrowserTestUtils.isVisible(body), "Main body is visible");
    332 
    333  let footer = document.getElementById("protections-popup-footer");
    334  ok(BrowserTestUtils.isVisible(footer), "Footer is visible");
    335 
    336  BrowserTestUtils.removeTab(tab);
    337 });
    338 
    339 /**
    340 * A test for the toggle switch flow
    341 */
    342 add_task(async function testToggleSwitchFlow() {
    343  // Open a tab.
    344  let tab = await BrowserTestUtils.openNewForegroundTab(
    345    gBrowser,
    346    "https://example.com"
    347  );
    348  await openProtectionsPanel();
    349 
    350  let popuphiddenPromise = BrowserTestUtils.waitForEvent(
    351    gProtectionsHandler._protectionsPopup,
    352    "popuphidden"
    353  );
    354  let popupShownPromise = BrowserTestUtils.waitForEvent(
    355    gProtectionsHandler._protectionsPopup,
    356    "popupshown"
    357  );
    358  let browserLoadedPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
    359 
    360  // Click the TP switch, from On -> Off.
    361  await clickToggle(gProtectionsHandler._protectionsPopupTPSwitch);
    362 
    363  // Check that the icon state has been changed.
    364  ok(
    365    gProtectionsHandler.iconBox.hasAttribute("hasException"),
    366    "The tracking protection icon state has been changed to disabled."
    367  );
    368 
    369  // The panel should be closed and the mini panel will show up after refresh.
    370  await popuphiddenPromise;
    371  await browserLoadedPromise;
    372  await popupShownPromise;
    373 
    374  ok(
    375    gProtectionsHandler._protectionsPopup.hasAttribute("toast"),
    376    "The protections popup should have the 'toast' attribute."
    377  );
    378 
    379  // Click on the mini panel and making sure the protection popup shows up.
    380  popupShownPromise = BrowserTestUtils.waitForEvent(
    381    gProtectionsHandler._protectionsPopup,
    382    "popupshown"
    383  );
    384  popuphiddenPromise = BrowserTestUtils.waitForEvent(
    385    gProtectionsHandler._protectionsPopup,
    386    "popuphidden"
    387  );
    388 
    389  // Simulate clicking on the mini panel text
    390  let buttonEl = document.getElementById(
    391    "protections-popup-toast-panel-tp-off-desc"
    392  );
    393  await EventUtils.synthesizeMouseAtCenter(buttonEl, {});
    394  await popuphiddenPromise;
    395  await popupShownPromise;
    396 
    397  ok(
    398    !gProtectionsHandler._protectionsPopup.hasAttribute("toast"),
    399    "The 'toast' attribute should be cleared on the protections popup."
    400  );
    401 
    402  // Click the TP switch again, from Off -> On.
    403  popuphiddenPromise = BrowserTestUtils.waitForEvent(
    404    gProtectionsHandler._protectionsPopup,
    405    "popuphidden"
    406  );
    407  popupShownPromise = BrowserTestUtils.waitForEvent(
    408    gProtectionsHandler._protectionsPopup,
    409    "popupshown"
    410  );
    411  browserLoadedPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser);
    412  await clickToggle(gProtectionsHandler._protectionsPopupTPSwitch);
    413 
    414  // Check that the icon state has been changed.
    415  ok(
    416    !gProtectionsHandler.iconBox.hasAttribute("hasException"),
    417    "The tracking protection icon state has been changed to enabled."
    418  );
    419 
    420  // Protections popup hidden -> Page refresh -> Mini panel shows up.
    421  await popuphiddenPromise;
    422  popuphiddenPromise = BrowserTestUtils.waitForEvent(
    423    gProtectionsHandler._protectionsPopup,
    424    "popuphidden"
    425  );
    426  await browserLoadedPromise;
    427  await popupShownPromise;
    428 
    429  ok(
    430    gProtectionsHandler._protectionsPopup.hasAttribute("toast"),
    431    "The protections popup should have the 'toast' attribute."
    432  );
    433 
    434  // Wait until the auto hide is happening.
    435  await popuphiddenPromise;
    436 
    437  // Clean up the TP state.
    438  ContentBlockingAllowList.remove(tab.linkedBrowser);
    439  BrowserTestUtils.removeTab(tab);
    440 });
    441 
    442 /**
    443 * A test for ensuring the tracking protection icon will show a correct
    444 * icon according to the TP enabling state.
    445 */
    446 add_task(async function testTrackingProtectionIcon() {
    447  // Open a tab and its protection panel.
    448  let tab = await BrowserTestUtils.openNewForegroundTab(
    449    gBrowser,
    450    "https://example.com"
    451  );
    452 
    453  let TPIcon = document.getElementById("tracking-protection-icon");
    454  // Check the icon url. It will show a shield icon if TP is enabled.
    455  is(
    456    gBrowser.ownerGlobal
    457      .getComputedStyle(TPIcon)
    458      .getPropertyValue("list-style-image"),
    459    `url("chrome://browser/skin/tracking-protection.svg")`,
    460    "The tracking protection icon shows a shield icon."
    461  );
    462 
    463  // Disable the tracking protection.
    464  let browserLoadedPromise = BrowserTestUtils.browserLoaded(
    465    tab.linkedBrowser,
    466    false,
    467    "https://example.com/"
    468  );
    469  gProtectionsHandler.disableForCurrentPage();
    470  await browserLoadedPromise;
    471 
    472  // Check that the tracking protection icon should show a strike-through shield
    473  // icon after page is reloaded.
    474  is(
    475    gBrowser.ownerGlobal
    476      .getComputedStyle(TPIcon)
    477      .getPropertyValue("list-style-image"),
    478    `url("chrome://browser/skin/tracking-protection-disabled.svg")`,
    479    "The tracking protection icon shows a strike through shield icon."
    480  );
    481 
    482  // Clean up the TP state.
    483  ContentBlockingAllowList.remove(tab.linkedBrowser);
    484  BrowserTestUtils.removeTab(tab);
    485 });
    486 
    487 /**
    488 * A test for ensuring the number of blocked trackers is displayed properly.
    489 */
    490 add_task(async function testNumberOfBlockedTrackers() {
    491  // First, clear the tracking database.
    492  await TrackingDBService.clearAll();
    493 
    494  // Open a tab.
    495  let tab = await BrowserTestUtils.openNewForegroundTab(
    496    gBrowser,
    497    "https://example.com"
    498  );
    499  await openProtectionsPanel();
    500 
    501  let trackerCounterBox = document.getElementById(
    502    "protections-popup-trackers-blocked-counter-box"
    503  );
    504  let trackerCounterDesc = document.getElementById(
    505    "protections-popup-trackers-blocked-counter-description"
    506  );
    507 
    508  // Check that whether the counter is not shown if the number of blocked
    509  // trackers is zero.
    510  ok(
    511    BrowserTestUtils.isHidden(trackerCounterBox),
    512    "The blocked tracker counter is hidden if there is no blocked tracker."
    513  );
    514 
    515  await closeProtectionsPanel();
    516 
    517  // Add one tracker into the database and check that the tracker counter is
    518  // properly shown.
    519  await addTrackerDataIntoDB(1);
    520 
    521  // A promise for waiting the `showing` attributes has been set to the counter
    522  // box. This means the database access is finished.
    523  let counterShownPromise = BrowserTestUtils.waitForAttribute(
    524    "showing",
    525    trackerCounterBox
    526  );
    527 
    528  await openProtectionsPanel();
    529  await counterShownPromise;
    530 
    531  // Check that the number of blocked trackers is shown.
    532  ok(
    533    BrowserTestUtils.isVisible(trackerCounterBox),
    534    "The blocked tracker counter is shown if there is one blocked tracker."
    535  );
    536  is(
    537    trackerCounterDesc.textContent,
    538    "1 Blocked",
    539    "The blocked tracker counter is correct."
    540  );
    541 
    542  await closeProtectionsPanel();
    543  await TrackingDBService.clearAll();
    544 
    545  // Add trackers into the database and check that the tracker counter is
    546  // properly shown as well as whether the pre-fetch is triggered by the
    547  // keyboard navigation.
    548  await addTrackerDataIntoDB(10);
    549 
    550  // We cannot wait for the change of "showing" attribute here since this
    551  // attribute will only be set if the previous counter is zero. Instead, we
    552  // wait for the change of the text content of the counter.
    553  let updateCounterPromise = new Promise(resolve => {
    554    let mut = new MutationObserver(() => {
    555      resolve();
    556      mut.disconnect();
    557    });
    558 
    559    mut.observe(trackerCounterDesc, {
    560      childList: true,
    561    });
    562  });
    563 
    564  await openProtectionsPanelWithKeyNav();
    565  await updateCounterPromise;
    566 
    567  // Check that the number of blocked trackers is shown.
    568  ok(
    569    BrowserTestUtils.isVisible(trackerCounterBox),
    570    "The blocked tracker counter is shown if there are more than one blocked tracker."
    571  );
    572  is(
    573    trackerCounterDesc.textContent,
    574    "10 Blocked",
    575    "The blocked tracker counter is correct."
    576  );
    577 
    578  await closeProtectionsPanel();
    579  await TrackingDBService.clearAll();
    580  BrowserTestUtils.removeTab(tab);
    581 });
    582 
    583 add_task(async function testSubViewTelemetry() {
    584  let items = [
    585    ["protections-popup-category-trackers", "trackers"],
    586    ["protections-popup-category-socialblock", "social"],
    587    ["protections-popup-category-cookies", "cookies"],
    588    ["protections-popup-category-cryptominers", "cryptominers"],
    589    ["protections-popup-category-fingerprinters", "fingerprinters"],
    590  ].map(item => [document.getElementById(item[0]), item[1]]);
    591 
    592  for (let [item, telemetryId] of items) {
    593    // eslint-disable-next-line @microsoft/sdl/no-insecure-url
    594    await BrowserTestUtils.withNewTab("http://www.example.com", async () => {
    595      await openProtectionsPanel();
    596 
    597      item.classList.remove("notFound"); // Force visible for test
    598      gProtectionsHandler._categoryItemOrderInvalidated = true;
    599      gProtectionsHandler.reorderCategoryItems();
    600 
    601      let viewShownEvent = BrowserTestUtils.waitForEvent(
    602        gProtectionsHandler._protectionsPopupMultiView,
    603        "ViewShown"
    604      );
    605      item.click();
    606      let panelView = (await viewShownEvent).originalTarget;
    607      checkClickTelemetry(telemetryId);
    608      let prefsTabPromise = BrowserTestUtils.waitForNewTab(
    609        gBrowser,
    610        "about:preferences#privacy"
    611      );
    612      panelView.querySelector(".panel-subview-footer-button").click();
    613      let prefsTab = await prefsTabPromise;
    614      BrowserTestUtils.removeTab(prefsTab);
    615      checkClickTelemetry("subview_settings", telemetryId);
    616    });
    617  }
    618 });
    619 
    620 /**
    621 * A test to make sure the TP state won't apply incorrectly if we quickly switch
    622 * tab after toggling the TP switch.
    623 */
    624 add_task(async function testQuickSwitchTabAfterTogglingTPSwitch() {
    625  const FIRST_TEST_SITE = "https://example.com/";
    626  const SECOND_TEST_SITE = "https://example.org/";
    627 
    628  // First, clear the tracking database.
    629  await TrackingDBService.clearAll();
    630 
    631  // Open two tabs with different origins.
    632  let tabOne = await BrowserTestUtils.openNewForegroundTab(
    633    gBrowser,
    634    FIRST_TEST_SITE
    635  );
    636  let tabTwo = await BrowserTestUtils.openNewForegroundTab(
    637    gBrowser,
    638    SECOND_TEST_SITE
    639  );
    640 
    641  // Open the protection panel of the second tab.
    642  await openProtectionsPanel();
    643 
    644  // A promise to check the reload happens on the second tab.
    645  let browserLoadedPromise = BrowserTestUtils.browserLoaded(
    646    tabTwo.linkedBrowser,
    647    false,
    648    SECOND_TEST_SITE
    649  );
    650 
    651  // Toggle the TP state and switch tab without waiting it to be finished.
    652  await clickToggle(gProtectionsHandler._protectionsPopupTPSwitch);
    653  gBrowser.selectedTab = tabOne;
    654 
    655  // Wait for the second tab to be reloaded.
    656  await browserLoadedPromise;
    657 
    658  // Check that the first tab is still with ETP enabled.
    659  ok(
    660    !ContentBlockingAllowList.includes(gBrowser.selectedBrowser),
    661    "The ETP state of the first tab is still enabled."
    662  );
    663 
    664  // Check the ETP is disabled on the second origin.
    665  ok(
    666    ContentBlockingAllowList.includes(tabTwo.linkedBrowser),
    667    "The ETP state of the second tab has been changed to disabled."
    668  );
    669 
    670  // Clean up the state of the allow list for the second tab.
    671  ContentBlockingAllowList.remove(tabTwo.linkedBrowser);
    672 
    673  BrowserTestUtils.removeTab(tabOne);
    674  BrowserTestUtils.removeTab(tabTwo);
    675 
    676  // Finally, clear the tracking database.
    677  await TrackingDBService.clearAll();
    678 });