Bug 1574930 - Part 3: Add a test case for making sure that the track counter displays properly and fix an issue for BrowserTestUtils.waitForAttribute(). r=nhnt11,johannh
authorTim Huang <tihuang@mozilla.com>
Thu, 22 Aug 2019 09:48:59 +0000
changeset 489427 5dbac06bc222985e95f30d6b372c64fcac8b817d
parent 489426 96854f5ed90d2bb723f76e5234da7d9961b1e327
child 489428 45f0e989e56eb48ce15325869777855b47e8941c
push id93329
push usertihuang@mozilla.com
push dateThu, 22 Aug 2019 11:41:54 +0000
treeherderautoland@5dbac06bc222 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnhnt11, johannh
bugs1574930
milestone70.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1574930 - Part 3: Add a test case for making sure that the track counter displays properly and fix an issue for BrowserTestUtils.waitForAttribute(). r=nhnt11,johannh This patch adds a test case to check the visibility of the track counter is correct in different situations, including zero tracker, one tracker and multiple trackers. Also, this patch fixes an issue that the BrowserTestUtils.waitForAttributes() won't work if the waiting attributes doesn't have a value or has an empty string as its value. We check the value of the observing attribute to verify if it is existing, however an empty string will be treated as a false, so it won't pass the check if the attribute doesn't have a value. Hence, we should use hasAttribute() instead of getAttribute() to check the existence of the attribute. Differential Revision: https://phabricator.services.mozilla.com/D42718
browser/base/content/test/siteProtections/browser_protections_UI.js
browser/base/content/test/siteProtections/head.js
testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
--- a/browser/base/content/test/siteProtections/browser_protections_UI.js
+++ b/browser/base/content/test/siteProtections/browser_protections_UI.js
@@ -18,16 +18,46 @@ function checkClickTelemetry(objectName,
       e[1] == "security.ui.protectionspopup" &&
       e[2] == "click" &&
       e[3] == objectName &&
       (!value || e[4] == value)
   );
   is(buttonEvents.length, 1, `recorded ${objectName} telemetry event`);
 }
 
+XPCOMUtils.defineLazyServiceGetter(
+  this,
+  "TrackingDBService",
+  "@mozilla.org/tracking-db-service;1",
+  "nsITrackingDBService"
+);
+
+XPCOMUtils.defineLazyGetter(this, "TRACK_DB_PATH", function() {
+  return OS.Path.join(OS.Constants.Path.profileDir, "protections.sqlite");
+});
+
+const { Sqlite } = ChromeUtils.import("resource://gre/modules/Sqlite.jsm");
+
+async function addTrackerDataIntoDB(count) {
+  const insertSQL =
+    "INSERT INTO events (type, count, timestamp)" +
+    "VALUES (:type, :count, date(:timestamp));";
+
+  let db = await Sqlite.openConnection({ path: TRACK_DB_PATH });
+  let date = new Date().toISOString();
+
+  await db.execute(insertSQL, {
+    type: TrackingDBService.TRACKERS_ID,
+    count,
+    timestamp: date,
+  });
+
+  await db.close();
+}
+
 add_task(async function setup() {
   await SpecialPowers.pushPrefEnv({
     set: [
       // Set the auto hide timing to 100ms for blocking the test less.
       ["browser.protections_panel.toast.timeout", 100],
       // Hide protections cards so as not to trigger more async messaging
       // when landing on the page.
       ["browser.contentblocking.report.monitor.enabled", false],
@@ -400,16 +430,112 @@ add_task(async function testTrackingProt
     "The tracking protection icon shows a strike through shield icon."
   );
 
   // Clean up the TP state.
   ContentBlockingAllowList.remove(tab.linkedBrowser);
   BrowserTestUtils.removeTab(tab);
 });
 
+/**
+ * A test for ensuring the number of blocked trackers is displayed properly.
+ */
+add_task(async function testNumberOfBlockedTrackers() {
+  // First, clear the tracking database.
+  await TrackingDBService.clearAll();
+
+  // Open a tab.
+  let tab = await BrowserTestUtils.openNewForegroundTab(
+    gBrowser,
+    "https://example.com"
+  );
+  await openProtectionsPanel();
+
+  let trackerCounterBox = document.getElementById(
+    "protections-popup-trackers-blocked-counter-box"
+  );
+  let trackerCounterDesc = document.getElementById(
+    "protections-popup-trackers-blocked-counter-description"
+  );
+
+  // Check that whether the counter is not shown if the number of blocked
+  // trackers is zero.
+  ok(
+    BrowserTestUtils.is_hidden(trackerCounterBox),
+    "The blocked tracker counter is hidden if there is no blocked tracker."
+  );
+
+  await closeProtectionsPanel();
+
+  // Add one tracker into the database and check that the tracker counter is
+  // properly shown.
+  await addTrackerDataIntoDB(1);
+
+  // A promise for waiting the `showing` attributes has been set to the counter
+  // box. This means the database access is finished.
+  let counterShownPromise = BrowserTestUtils.waitForAttribute(
+    "showing",
+    trackerCounterBox
+  );
+
+  await openProtectionsPanel();
+  await counterShownPromise;
+
+  // Check that the number of blocked trackers is shown.
+  ok(
+    BrowserTestUtils.is_visible(trackerCounterBox),
+    "The blocked tracker counter is shown if there is one blocked tracker."
+  );
+  is(
+    trackerCounterDesc.textContent,
+    "1 Blocked",
+    "The blocked tracker counter is correct."
+  );
+
+  await closeProtectionsPanel();
+  await TrackingDBService.clearAll();
+
+  // Add trackers into the database and check that the tracker counter is
+  // properly shown as well as whether the pre-fetch is triggered by the
+  // keyboard navigation.
+  await addTrackerDataIntoDB(10);
+
+  // We cannot wait for the change of "showing" attribute here since this
+  // attribute will only be set if the previous counter is zero. Instead, we
+  // wait for the change of the text content of the counter.
+  let updateCounterPromise = new Promise(resolve => {
+    let mut = new MutationObserver(mutations => {
+      resolve();
+      mut.disconnect();
+    });
+
+    mut.observe(trackerCounterDesc, {
+      childList: true,
+    });
+  });
+
+  await openProtectionsPanelWithKeyNav();
+  await updateCounterPromise;
+
+  // Check that the number of blocked trackers is shown.
+  ok(
+    BrowserTestUtils.is_visible(trackerCounterBox),
+    "The blocked tracker counter is shown if there are more than one blocked tracker."
+  );
+  is(
+    trackerCounterDesc.textContent,
+    "10 Blocked",
+    "The blocked tracker counter is correct."
+  );
+
+  await closeProtectionsPanel();
+  await TrackingDBService.clearAll();
+  BrowserTestUtils.removeTab(tab);
+});
+
 add_task(async function testSubViewTelemetry() {
   let items = [
     ["protections-popup-category-tracking-protection", "trackers"],
     ["protections-popup-category-socialblock", "social"],
     ["protections-popup-category-cookies", "cookies"],
     ["protections-popup-category-cryptominers", "cryptominers"],
     ["protections-popup-category-fingerprinters", "fingerprinters"],
   ].map(item => [document.getElementById(item[0]), item[1]]);
--- a/browser/base/content/test/siteProtections/head.js
+++ b/browser/base/content/test/siteProtections/head.js
@@ -13,19 +13,51 @@ async function openProtectionsPanel(toas
   let popupShownPromise = BrowserTestUtils.waitForEvent(
     protectionsPopup,
     "popupshown"
   );
   let shieldIconContainer = document.getElementById(
     "tracking-protection-icon-container"
   );
 
-  // Focus to the icon container in order to fetch tracker count.
-  shieldIconContainer.focus();
+  // Move out than move over the shield icon to trigger the hover event in
+  // order to fetch tracker count.
+  EventUtils.synthesizeMouseAtCenter(gURLBar.textbox, {
+    type: "mousemove",
+  });
+  EventUtils.synthesizeMouseAtCenter(shieldIconContainer, {
+    type: "mousemove",
+  });
 
   if (!toast) {
     EventUtils.synthesizeMouseAtCenter(shieldIconContainer, {});
   } else {
     gProtectionsHandler.showProtectionsPopup({ toast });
   }
 
   await popupShownPromise;
 }
+
+async function openProtectionsPanelWithKeyNav() {
+  let popupShownPromise = BrowserTestUtils.waitForEvent(
+    protectionsPopup,
+    "popupshown"
+  );
+
+  gURLBar.focus();
+
+  // This will trigger the focus event for the shield icon for pre-fetching
+  // the tracker count.
+  EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true });
+  EventUtils.synthesizeKey("KEY_Enter", {});
+
+  await popupShownPromise;
+}
+
+async function closeProtectionsPanel() {
+  let popuphiddenPromise = BrowserTestUtils.waitForEvent(
+    protectionsPopup,
+    "popuphidden"
+  );
+
+  PanelMultiView.hidePopup(protectionsPopup);
+  await popuphiddenPromise;
+}
--- a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
+++ b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
@@ -1803,17 +1803,17 @@ var BrowserTestUtils = {
    *
    * @returns {Promise}
    */
   waitForAttribute(attr, element, value) {
     let MutationObserver = element.ownerGlobal.MutationObserver;
     return new Promise(resolve => {
       let mut = new MutationObserver(mutations => {
         if (
-          (!value && element.getAttribute(attr)) ||
+          (!value && element.hasAttribute(attr)) ||
           (value && element.getAttribute(attr) === value)
         ) {
           resolve();
           mut.disconnect();
         }
       });
 
       mut.observe(element, { attributeFilter: [attr] });