Bug 1307689 - Regression tests. r=mossop
authorMike Conley <mconley@mozilla.com>
Thu, 26 Jan 2017 17:55:35 -0500
changeset 469887 ae4a32972c9412ad22ba83c56ff17f7b648ceefc
parent 469886 98654213e2473c9aee2984e67c3659d2ebed27c1
child 469888 6905cedb8cad61a1cda9a2d74c07fc001619c998
push id43881
push userbmo:gps@mozilla.com
push dateThu, 02 Feb 2017 23:49:03 +0000
reviewersmossop
bugs1307689
milestone54.0a1
Bug 1307689 - Regression tests. r=mossop MozReview-Commit-ID: 7SFqRNtMZVs
browser/base/content/test/tabs/browser.ini
browser/base/content/test/tabs/browser_abandonment_telemetry.js
--- a/browser/base/content/test/tabs/browser.ini
+++ b/browser/base/content/test/tabs/browser.ini
@@ -1,12 +1,13 @@
 [DEFAULT]
 support-files =
   dummy_page.html
 
+[browser_abandonment_telemetry.js]
 [browser_allow_process_switches_despite_related_browser.js]
 [browser_tabSpinnerProbe.js]
 skip-if = !e10s # Tab spinner is e10s only.
 [browser_tabSwitchPrintPreview.js]
 skip-if = os == 'mac'
 [browser_navigatePinnedTab.js]
 [browser_opened_file_tab_navigated_to_web.js]
 [browser_reload_deleted_file.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabs/browser_abandonment_telemetry.js
@@ -0,0 +1,305 @@
+"use strict";
+
+const {TabStateFlusher} = Cu.import("resource:///modules/sessionstore/TabStateFlusher.jsm", {});
+
+// Keep this in sync with the order in Histograms.json for
+// BUSY_TAB_ABANDONED
+const CATEGORIES = [
+  "stop",
+  "back",
+  "forward",
+  "historyNavigation",
+  "reload",
+  "tabClosed",
+  "newURI",
+];
+
+const PAGE_2 = "data:text/html,<html>Page 2</html>";
+
+/**
+ * This little framework helps to extract the unique things
+ * involved in testing each category of the BUSY_TAB_ABANDONED
+ * probe from all of the common things. The little framework
+ * in this test will take each item in PROBE_TEST, let it
+ * do some test preparation, then create a "busy" tab to be
+ * manipulated by the test. The "category" of the test will then
+ * be used to determine if the appropriate index in the
+ * histogram was bumped.
+ *
+ * Here's a more verbose breakdown of what each PROBE_TEST
+ * should supply:
+ *
+ * name (String):
+ *   Human readable description of the test. This is dumped
+ *   out via info().
+ *
+ * category (String):
+ *   The string representation of the index that will get
+ *   incremented in the BUSY_TAB_ABANDONED probe. This should
+ *   be a value inside CATEGORIES.
+ *
+ * prepare (function*)
+ *   A function that can yield Promises. This will be run once
+ *   we have a brand new browser to deal with, and should be used by
+ *   the PROBE_TEST to do any history preparation before the browser
+ *   is made to appear "busy" and is tested.
+ *
+ *   @param browser (<xul:browser>)
+ *          The newly created browser that the test will use.
+ *
+ * doAction (function*)
+ *   A function that can yield Promises. This will be run once
+ *   the browser appears busy, and should cause the user action
+ *   that will change the BUSY_TAB_ABANDONED probe.
+ *
+ *   @param browser (<xul:browser>)
+ *          The busy browser to perform the action on.
+ */
+const PROBE_TESTS = [
+
+  // Test stopping the tab
+  {
+    name: "Stopping the browser",
+
+    category: "stop",
+
+    * prepare(browser) {},
+
+    * doAction(browser) {
+      document.getElementById("Browser:Stop").doCommand();
+    },
+  },
+
+  // Test going back to a previous page
+  {
+    name: "Going back to a previous page",
+
+    category: "back",
+
+    * prepare(browser) {
+      browser.loadURI(PAGE_2);
+      yield BrowserTestUtils.browserLoaded(browser);
+    },
+
+    * doAction(browser) {
+      let pageShow =
+        BrowserTestUtils.waitForContentEvent(browser, "pageshow");
+      document.getElementById("Browser:Back").doCommand();
+      yield pageShow;
+    },
+  },
+
+  // Test going forward to a previous page
+  {
+    name: "Going forward to the next page",
+
+    category: "forward",
+
+    * prepare(browser) {
+      browser.loadURI(PAGE_2);
+      yield BrowserTestUtils.browserLoaded(browser);
+      let pageShow =
+        BrowserTestUtils.waitForContentEvent(browser, "pageshow");
+      browser.goBack();
+      yield pageShow;
+    },
+
+    * doAction(browser) {
+      let pageShow =
+        BrowserTestUtils.waitForContentEvent(browser, "pageshow");
+      document.getElementById("Browser:Forward").doCommand();
+      yield pageShow;
+    },
+  },
+
+  // Test going backwards more than one page back via gotoIndex
+  {
+    name: "Going backward to a previous page via gotoIndex",
+
+    category: "historyNavigation",
+
+    * prepare(browser) {
+      browser.loadURI(PAGE_2);
+      yield BrowserTestUtils.browserLoaded(browser);
+      browser.loadURI("http://example.com");
+      yield BrowserTestUtils.browserLoaded(browser);
+      yield TabStateFlusher.flush(browser);
+    },
+
+    * doAction(browser) {
+      let pageShow =
+        BrowserTestUtils.waitForContentEvent(browser, "pageshow");
+      synthesizeHistoryNavigationToIndex(0);
+      yield pageShow;
+    },
+  },
+
+  // Test going forwards more than one page back via gotoIndex
+  {
+    name: "Going forward to a previous page via gotoIndex",
+
+    category: "historyNavigation",
+
+    * prepare(browser) {
+      browser.loadURI(PAGE_2);
+      yield BrowserTestUtils.browserLoaded(browser);
+      browser.loadURI("http://example.com");
+      yield BrowserTestUtils.browserLoaded(browser);
+      let pageShow =
+        BrowserTestUtils.waitForContentEvent(browser, "pageshow");
+      browser.gotoIndex(0);
+      yield pageShow;
+      yield TabStateFlusher.flush(browser);
+    },
+
+    * doAction(browser) {
+      let pageShow =
+        BrowserTestUtils.waitForContentEvent(browser, "pageshow");
+      synthesizeHistoryNavigationToIndex(2);
+      yield pageShow;
+    },
+  },
+
+  // Test reloading the tab
+  {
+    name: "Reloading the browser",
+
+    category: "reload",
+
+    * prepare(browser) {},
+
+    * doAction(browser) {
+      document.getElementById("Browser:Reload").doCommand();
+      yield BrowserTestUtils.browserLoaded(browser);
+    },
+  },
+
+  // Testing closing the tab is done in its own test later on
+  // in this file.
+
+  // Test browsing to a new URL
+  {
+    name: "Browsing to a new URL",
+
+    category: "newURI",
+
+    * prepare(browser) {},
+
+    * doAction(browser) {
+      openUILinkIn(PAGE_2, "current");
+      yield BrowserTestUtils.browserLoaded(browser);
+    },
+  },
+]
+
+/**
+ * Takes a Telemetry histogram snapshot and makes sure
+ * that the index for that value (as defined by CATEGORIES)
+ * has a count of 1, and that it's the only value that
+ * has been incremented.
+ *
+ * @param snapshot (Object)
+ *        The Telemetry histogram snapshot to examine.
+ * @param category (String)
+ *        The category in CATEGORIES whose index we expect to have
+ *        been set to 1.
+ */
+function assertOnlyOneTypeSet(snapshot, category) {
+  let categoryIndex = CATEGORIES.indexOf(category);
+  Assert.equal(snapshot.counts[categoryIndex], 1,
+               `Should have seen the ${category} count increment.`);
+  // Use Array.prototype.reduce to sum up all of the
+  // snapshot.count entries
+  Assert.equal(snapshot.counts.reduce((a, b) => a + b), 1,
+               "Should only be 1 collected value.");
+}
+
+/**
+ * A helper function for simulating clicking on the history
+ * navigation popup menu that you get if you click and hold
+ * on the back or forward buttons when you have some browsing
+ * history.
+ *
+ * @param index (int)
+ *        The index for the menuitem we want to simulate
+ *        clicking on.
+ */
+function synthesizeHistoryNavigationToIndex(index) {
+  let popup = document.getElementById("backForwardMenu");
+  // I don't want to deal with popup listening - that's
+  // notoriously flake-y in automated tests. I'll just
+  // directly call the function that populates the menu.
+  FillHistoryMenu(popup);
+  Assert.ok(popup.childElementCount > 0,
+            "Should have some items in the back/forward menu");
+  let menuitem = popup.querySelector(`menuitem[index="${index}"]`);
+  Assert.ok(menuitem, `Should find a menuitem with index ${index}`);
+  // Now pretend we clicked on the right item.
+  let cmdEvent = new CustomEvent("command", {
+    bubbles: true,
+    cancelable: true,
+  });
+  menuitem.dispatchEvent(cmdEvent);
+}
+
+/**
+ * Goes through each of the categories for the BUSY_TAB_ABANDONED
+ * probe, and tests that they're properly changed.
+ */
+add_task(function* test_probes() {
+  let oldCanRecord = Services.telemetry.canRecordExtended;
+  Services.telemetry.canRecordExtended = true;
+
+  registerCleanupFunction(() => {
+    Services.telemetry.canRecordExtended = oldCanRecord;
+  });
+
+  let histogram = Services.telemetry
+                          .getHistogramById("BUSY_TAB_ABANDONED");
+
+  // If you want to add new tests for probes that don't involve
+  // the tab or window hosting the tab closing, see the documentation
+  // above PROBE_TESTS for how to hook into this little framework.
+  for (let probeTest of PROBE_TESTS) {
+    yield BrowserTestUtils.withNewTab({
+      gBrowser,
+      url: "http://example.com",
+    }, function*(browser) {
+      let tab = gBrowser.getTabForBrowser(browser);
+      info(`Test: "${probeTest.name}"`);
+
+      yield* probeTest.prepare(browser);
+      // Instead of trying to fiddle with network state or
+      // anything, we'll just set this attribute to fool our
+      // telemetry probes into thinking the browser is in the
+      // middle of loading some resources.
+      tab.setAttribute("busy", true);
+
+      histogram.clear();
+      yield* probeTest.doAction(browser);
+      let snapshot = histogram.snapshot();
+      assertOnlyOneTypeSet(snapshot, probeTest.category);
+    });
+  }
+
+  // The above tests used BrowserTestUtils.withNewTab, which is
+  // fine for almost all categories for this probe, except for
+  // "tabClosed", since withNewTab closes the tab automatically
+  // before resolving, which doesn't work well for a tabClosed
+  // test in the above framework. So the tabClosed tests are
+  // done separately below.
+
+  histogram.clear();
+  // Now test that we can close a busy tab and get the tabClosed
+  // measurement bumped.
+  let newTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser);
+  // As above, instead of trying to fiddle with network state
+  // or anything, we'll just set this attribute to fool our
+  // telemetry probes into thinking the browser is in the
+  // middle of loading some resources.
+  newTab.setAttribute("busy", true);
+
+  yield BrowserTestUtils.removeTab(newTab);
+  let snapshot = histogram.snapshot();
+  assertOnlyOneTypeSet(snapshot, "tabClosed");
+});