Bug 1471403 - Part 2 - Lazify the creation of "notificationbox" elements. r=dao,bgrins
authorPaolo Amadini <paolo.mozmail@amadzone.org>
Fri, 09 Nov 2018 14:38:49 +0000
changeset 501969 a2a92421b50f91f29ed416eafd8f86f62dfdab45
parent 501968 6c594f12cc041379fe976eb53f82bce34f7a84c9
child 501970 5fc40fe6b994e684f9db2c67b0c4d7e8be5540df
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdao, bgrins
bugs1471403
milestone65.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 1471403 - Part 2 - Lazify the creation of "notificationbox" elements. r=dao,bgrins Differential Revision: https://phabricator.services.mozilla.com/D10892
browser/base/content/browser-captivePortal.js
browser/base/content/browser-data-submission-info-bar.js
browser/base/content/browser.css
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/tabbrowser.js
browser/base/content/test/captivePortal/head.js
browser/base/content/test/general/browser_datachoices_notification.js
browser/base/content/test/general/browser_storagePressure_notification.js
browser/base/content/test/general/head.js
browser/components/nsBrowserGlue.js
browser/components/tests/browser/browser_bug538331.js
browser/modules/ContentCrashHandlers.jsm
browser/modules/ProcessHangMonitor.jsm
browser/modules/test/browser/browser_ProcessHangNotifications.js
browser/modules/test/browser/browser_UnsubmittedCrashHandler.js
devtools/shared/fronts/csscoverage.js
testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
toolkit/components/normandy/lib/Heartbeat.jsm
toolkit/components/normandy/test/browser/browser_Heartbeat.js
--- a/browser/base/content/browser-captivePortal.js
+++ b/browser/base/content/browser-captivePortal.js
@@ -18,18 +18,18 @@ var CaptivePortalWatcher = {
    */
   _delayedCaptivePortalDetectedInProgress: false,
 
   // In the situation above, this is set to true while we wait for the recheck.
   // This flag exists so that tests can appropriately simulate a recheck.
   _waitingForRecheck: false,
 
   get _captivePortalNotification() {
-    let nb = document.getElementById("high-priority-global-notificationbox");
-    return nb.getNotificationWithValue(this.PORTAL_NOTIFICATION_VALUE);
+    return gHighPriorityNotificationBox.getNotificationWithValue(
+                                           this.PORTAL_NOTIFICATION_VALUE);
   },
 
   get canonicalURL() {
     return Services.prefs.getCharPref("captivedetect.canonicalURL");
   },
 
   get _browserBundle() {
     delete this._browserBundle;
@@ -223,19 +223,19 @@ var CaptivePortalWatcher = {
 
     let closeHandler = (aEventName) => {
       if (aEventName != "removed") {
         return;
       }
       gBrowser.tabContainer.removeEventListener("TabSelect", this);
     };
 
-    let nb = document.getElementById("high-priority-global-notificationbox");
-    nb.appendNotification(message, this.PORTAL_NOTIFICATION_VALUE, "",
-                          nb.PRIORITY_INFO_MEDIUM, buttons, closeHandler);
+    gHighPriorityNotificationBox.appendNotification(
+      message, this.PORTAL_NOTIFICATION_VALUE, "",
+      gHighPriorityNotificationBox.PRIORITY_INFO_MEDIUM, buttons, closeHandler);
 
     gBrowser.tabContainer.addEventListener("TabSelect", this);
   },
 
   _removeNotification() {
     let n = this._captivePortalNotification;
     if (!n || !n.parentNode) {
       return;
--- a/browser/base/content/browser-data-submission-info-bar.js
+++ b/browser/base/content/browser-data-submission-info-bar.js
@@ -10,21 +10,16 @@ const LOGGER_PREFIX = "DataNotificationI
 var gDataNotificationInfoBar = {
   _OBSERVERS: [
     "datareporting:notify-data-policy:request",
     "datareporting:notify-data-policy:close",
   ],
 
   _DATA_REPORTING_NOTIFICATION: "data-reporting",
 
-  get _notificationBox() {
-    delete this._notificationBox;
-    return this._notificationBox = document.getElementById("global-notificationbox");
-  },
-
   get _log() {
     let Log = ChromeUtils.import("resource://gre/modules/Log.jsm", {}).Log;
     delete this._log;
     return this._log = Log.repository.getLoggerWithMessagePrefix(LOGGER_NAME, LOGGER_PREFIX);
   },
 
   init() {
     window.addEventListener("unload", () => {
@@ -34,17 +29,17 @@ var gDataNotificationInfoBar = {
     });
 
     for (let o of this._OBSERVERS) {
       Services.obs.addObserver(this, o, true);
     }
   },
 
   _getDataReportingNotification(name = this._DATA_REPORTING_NOTIFICATION) {
-    return this._notificationBox.getNotificationWithValue(name);
+    return gNotificationBox.getNotificationWithValue(name);
   },
 
   _displayDataPolicyInfoBar(request) {
     if (this._getDataReportingNotification()) {
       return;
     }
 
     let brandBundle = document.getElementById("bundle_brand");
@@ -63,21 +58,21 @@ var gDataNotificationInfoBar = {
       popup: null,
       callback: () => {
         this._actionTaken = true;
         window.openPreferences("privacy-reports", {origin: "dataReporting"});
       },
     }];
 
     this._log.info("Creating data reporting policy notification.");
-    this._notificationBox.appendNotification(
+    gNotificationBox.appendNotification(
       message,
       this._DATA_REPORTING_NOTIFICATION,
       null,
-      this._notificationBox.PRIORITY_INFO_HIGH,
+      gNotificationBox.PRIORITY_INFO_HIGH,
       buttons,
       event => {
         if (event == "removed") {
           Services.obs.notifyObservers(null, "datareporting:notify-data-policy:close");
         }
       }
     );
     // It is important to defer calling onUserNotifyComplete() until we're
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -367,18 +367,17 @@ toolbarpaletteitem {
 }
 %endif
 
 #main-window[inFullscreen][inDOMFullscreen] #navigator-toolbox,
 #main-window[inFullscreen][inDOMFullscreen] #fullscr-toggler,
 #main-window[inFullscreen][inDOMFullscreen] #sidebar-box,
 #main-window[inFullscreen][inDOMFullscreen] #sidebar-splitter,
 #main-window[inFullscreen]:not([OSXLionFullscreen]) toolbar:not([fullscreentoolbar=true]),
-#main-window[inFullscreen] #global-notificationbox,
-#main-window[inFullscreen] #high-priority-global-notificationbox {
+#main-window[inFullscreen] .global-notificationbox {
   visibility: collapse;
 }
 
 #navigator-toolbox[fullscreenShouldAnimate] {
   transition: 1.5s margin-top ease-out;
 }
 
 /* Rules to help integrate WebExtension buttons */
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -289,16 +289,48 @@ Object.defineProperty(this, "gNavToolbox
   configurable: true,
   enumerable: true,
   get() {
     delete this.gNavToolbox;
     return this.gNavToolbox = document.getElementById("navigator-toolbox");
   },
 });
 
+// High priority notification bars shown at the top of the window.
+Object.defineProperty(this, "gHighPriorityNotificationBox", {
+  configurable: true,
+  enumerable: true,
+  get() {
+    delete this.gHighPriorityNotificationBox;
+
+    let notificationbox = document.createXULElement("notificationbox");
+    notificationbox.className = "global-notificationbox";
+    notificationbox.setAttribute("notificationside", "top");
+    document.getElementById("appcontent").prepend(notificationbox);
+
+    return this.gHighPriorityNotificationBox = notificationbox;
+  },
+});
+
+// Regular notification bars shown at the bottom of the window.
+Object.defineProperty(this, "gNotificationBox", {
+  configurable: true,
+  enumerable: true,
+  get() {
+    delete this.gNotificationBox;
+
+    let notificationbox = document.createXULElement("notificationbox");
+    notificationbox.className = "global-notificationbox";
+    notificationbox.setAttribute("notificationside", "bottom");
+    document.getElementById("browser-bottombox").appendChild(notificationbox);
+
+    return this.gNotificationBox = notificationbox;
+  },
+});
+
 // Smart getter for the findbar.  If you don't wish to force the creation of
 // the findbar, check gFindBarInitialized first.
 
 Object.defineProperty(this, "gFindBar", {
   configurable: true,
   enumerable: true,
   get() {
     return gBrowser.getCachedFindBar();
@@ -522,18 +554,17 @@ const gStoragePressureObserver = {
   _lastNotificationTime: -1,
 
   observe(subject, topic, data) {
     if (topic != "QuotaManager::StoragePressure") {
       return;
     }
 
     const NOTIFICATION_VALUE = "storage-pressure-notification";
-    let notificationBox = document.getElementById("high-priority-global-notificationbox");
-    if (notificationBox.getNotificationWithValue(NOTIFICATION_VALUE)) {
+    if (gHighPriorityNotificationBox.getNotificationWithValue(NOTIFICATION_VALUE)) {
       // Do not display the 2nd notification when there is already one
       return;
     }
 
     // Don't display notification twice within the given interval.
     // This is because
     //   - not to annoy user
     //   - give user some time to clean space.
@@ -592,18 +623,19 @@ const gStoragePressureObserver = {
         callback(notificationBar, button) {
           // The advanced subpanes are only supported in the old organization, which will
           // be removed by bug 1349689.
           openPreferences("privacy-sitedata", { origin: "storagePressure" });
         },
       });
     }
 
-    notificationBox.appendNotification(
-      msg, NOTIFICATION_VALUE, null, notificationBox.PRIORITY_WARNING_HIGH, buttons, null);
+    gHighPriorityNotificationBox.appendNotification(
+      msg, NOTIFICATION_VALUE, null,
+      gHighPriorityNotificationBox.PRIORITY_WARNING_HIGH, buttons, null);
   },
 };
 
 var gPopupBlockerObserver = {
   handleEvent(aEvent) {
     if (aEvent.originalTarget != gBrowser.selectedBrowser)
       return;
 
@@ -3498,20 +3530,20 @@ var PrintPreviewListener = {
     this._sidebarCommand = SidebarUI.currentID;
     SidebarUI.hide();
 
     this._chromeState.findOpen = gFindBarInitialized && !gFindBar.hidden;
     if (gFindBarInitialized)
       gFindBar.close();
 
     gBrowser.getNotificationBox().hidden = true;
-    document.getElementById("global-notificationbox").hidden = true;
+    gNotificationBox.hidden = true;
   },
   _showChrome() {
-    document.getElementById("global-notificationbox").hidden = false;
+    gNotificationBox.hidden = false;
     gBrowser.getNotificationBox().hidden = false;
 
     if (this._chromeState.findOpen) {
       gLazyFindCommand("open");
     }
 
     if (this._chromeState.sidebarOpen) {
       SidebarUI.show(this._sidebarCommand);
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -1322,17 +1322,17 @@ xmlns="http://www.w3.org/1999/xhtml"
           <toolbarbutton id="sidebar-close" class="close-icon tabbable" tooltiptext="&sidebarCloseButton.tooltip;" oncommand="SidebarUI.hide();"/>
         </sidebarheader>
         <browser id="sidebar" flex="1" autoscroll="false" disablehistory="true" disablefullscreen="true"
                   style="min-width: 14em; width: 18em; max-width: 36em;" tooltip="aHTMLTooltip"/>
       </vbox>
 
       <splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" hidden="true"/>
       <vbox id="appcontent" flex="1">
-        <notificationbox id="high-priority-global-notificationbox" notificationside="top"/>
+        <!-- gHighPriorityNotificationBox will be added here lazily. -->
         <tabbox id="tabbrowser-tabbox"
                 flex="1" tabcontainer="tabbrowser-tabs">
           <tabpanels id="tabbrowser-tabpanels"
                      flex="1" class="plain" selectedIndex="0"/>
         </tabbox>
       </vbox>
       <vbox id="browser-border-end" hidden="true" layer="true"/>
     </hbox>
@@ -1365,12 +1365,12 @@ xmlns="http://www.w3.org/1999/xhtml"
       &pointerlockWarning.afterDomain.label;
     </html:div>
     <html:div class="pointerlockfswarning-generic-text">
       &pointerlockWarning.generic.label;
     </html:div>
   </html:div>
 
   <vbox id="browser-bottombox" layer="true">
-    <notificationbox id="global-notificationbox" notificationside="bottom"/>
+    <!-- gNotificationBox will be added here lazily. -->
   </vbox>
 
 </window>
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -649,17 +649,24 @@ window._gBrowser = {
     return this.getBrowserContainer(aBrowser).parentNode;
   },
 
   getBrowserContainer(aBrowser) {
     return (aBrowser || this.selectedBrowser).parentNode.parentNode;
   },
 
   getNotificationBox(aBrowser) {
-    return this.getBrowserContainer(aBrowser).firstElementChild;
+    let container = this.getBrowserContainer(aBrowser);
+    let notificationbox = container.firstElementChild;
+    if (notificationbox.localName != "notificationbox") {
+      notificationbox = document.createXULElement("notificationbox");
+      notificationbox.setAttribute("notificationside", "top");
+      container.prepend(notificationbox);
+    }
+    return notificationbox;
   },
 
   getTabModalPromptBox(aBrowser) {
     let browser = (aBrowser || this.selectedBrowser);
     if (!browser.tabModalPromptBox) {
       browser.tabModalPromptBox = new TabModalPromptBox(browser);
     }
     return browser.tabModalPromptBox;
--- a/browser/base/content/test/captivePortal/head.js
+++ b/browser/base/content/test/captivePortal/head.js
@@ -93,19 +93,18 @@ async function focusWindowAndWaitForPort
 function ensurePortalTab(win) {
   // For the tests that call this function, it's enough to ensure there
   // are two tabs in the window - the default tab and the portal tab.
   is(win.gBrowser.tabs.length, 2,
     "There should be a captive portal tab in the window.");
 }
 
 function ensurePortalNotification(win) {
-  let notificationBox =
-    win.document.getElementById("high-priority-global-notificationbox");
-  let notification = notificationBox.getNotificationWithValue(PORTAL_NOTIFICATION_VALUE);
+  let notification = win.gHighPriorityNotificationBox.getNotificationWithValue(
+                                                  PORTAL_NOTIFICATION_VALUE);
   isnot(notification, null,
     "There should be a captive portal notification in the window.");
   return notification;
 }
 
 // Helper to test whether the "Show Login Page" is visible in the captive portal
 // notification (it should be hidden when the portal tab is selected).
 function testShowLoginPageButtonVisibility(notification, visibility) {
@@ -117,19 +116,18 @@ function testShowLoginPageButtonVisibili
 }
 
 function ensureNoPortalTab(win) {
   is(win.gBrowser.tabs.length, 1,
     "There should be no captive portal tab in the window.");
 }
 
 function ensureNoPortalNotification(win) {
-  let notificationBox =
-    win.document.getElementById("high-priority-global-notificationbox");
-  is(notificationBox.getNotificationWithValue(PORTAL_NOTIFICATION_VALUE), null,
+  is(win.gHighPriorityNotificationBox
+    .getNotificationWithValue(PORTAL_NOTIFICATION_VALUE), null,
     "There should be no captive portal notification in the window.");
 }
 
 /**
  * Some tests open a new window and close it later. When the window is closed,
  * the original window opened by mochitest gains focus, generating an
  * activate event. If the next test also opens a new window
  * before this event has a chance to fire, CaptivePortalWatcher picks
--- a/browser/base/content/test/general/browser_datachoices_notification.js
+++ b/browser/base/content/test/general/browser_datachoices_notification.js
@@ -115,43 +115,41 @@ function clearAcceptedPolicy() {
 }
 
 add_task(async function test_single_window() {
   clearAcceptedPolicy();
 
   // Close all the notifications, then try to trigger the data choices infobar.
   await closeAllNotifications();
 
-  let notificationBox = document.getElementById("global-notificationbox");
-
   // Make sure that we have a coherent initial state.
   Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0), 0,
                "No version should be set on init.");
   Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_DATE, 0), 0,
                "No date should be set on init.");
   Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(),
             "User not notified about datareporting policy.");
 
-  let alertShownPromise = promiseWaitForAlertActive(notificationBox);
+  let alertShownPromise = promiseWaitForAlertActive(gNotificationBox);
   Assert.ok(!TelemetryReportingPolicy.canUpload(),
             "User should not be allowed to upload.");
 
   // Wait for the infobar to be displayed.
   triggerInfoBar(10 * 1000);
   await alertShownPromise;
 
-  Assert.equal(notificationBox.allNotifications.length, 1, "Notification Displayed.");
+  Assert.equal(gNotificationBox.allNotifications.length, 1, "Notification Displayed.");
   Assert.ok(TelemetryReportingPolicy.canUpload(), "User should be allowed to upload now.");
 
   await promiseNextTick();
-  let promiseClosed = promiseWaitForNotificationClose(notificationBox.currentNotification);
-  await checkInfobarButton(notificationBox.currentNotification);
+  let promiseClosed = promiseWaitForNotificationClose(gNotificationBox.currentNotification);
+  await checkInfobarButton(gNotificationBox.currentNotification);
   await promiseClosed;
 
-  Assert.equal(notificationBox.allNotifications.length, 0, "No notifications remain.");
+  Assert.equal(gNotificationBox.allNotifications.length, 0, "No notifications remain.");
 
   // Check that we are still clear to upload and that the policy data is saved.
   Assert.ok(TelemetryReportingPolicy.canUpload());
   Assert.equal(TelemetryReportingPolicy.testIsUserNotified(), true,
                "User notified about datareporting policy.");
   Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0), TEST_POLICY_VERSION,
                "Version pref set.");
   Assert.greater(parseInt(Preferences.get(PREF_ACCEPTED_POLICY_DATE, null), 10), -1,
@@ -163,47 +161,41 @@ add_task(async function test_multiple_wi
 
   // Close all the notifications, then try to trigger the data choices infobar.
   await closeAllNotifications();
 
   // Ensure we see the notification on all windows and that action on one window
   // results in dismiss on every window.
   let otherWindow = await BrowserTestUtils.openNewBrowserWindow();
 
-  // Get the notification box for both windows.
-  let notificationBoxes = [
-    document.getElementById("global-notificationbox"),
-    otherWindow.document.getElementById("global-notificationbox"),
-  ];
-
-  Assert.ok(notificationBoxes[1], "2nd window has a global notification box.");
+  Assert.ok(otherWindow.gNotificationBox, "2nd window has a global notification box.");
 
   // Make sure that we have a coherent initial state.
   Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0), 0, "No version should be set on init.");
   Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_DATE, 0), 0, "No date should be set on init.");
   Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(), "User not notified about datareporting policy.");
 
   let showAlertPromises = [
-    promiseWaitForAlertActive(notificationBoxes[0]),
-    promiseWaitForAlertActive(notificationBoxes[1]),
+    promiseWaitForAlertActive(gNotificationBox),
+    promiseWaitForAlertActive(otherWindow.gNotificationBox),
   ];
 
   Assert.ok(!TelemetryReportingPolicy.canUpload(),
             "User should not be allowed to upload.");
 
   // Wait for the infobars.
   triggerInfoBar(10 * 1000);
   await Promise.all(showAlertPromises);
 
   // Both notification were displayed. Close one and check that both gets closed.
   let closeAlertPromises = [
-    promiseWaitForNotificationClose(notificationBoxes[0].currentNotification),
-    promiseWaitForNotificationClose(notificationBoxes[1].currentNotification),
+    promiseWaitForNotificationClose(gNotificationBox.currentNotification),
+    promiseWaitForNotificationClose(otherWindow.gNotificationBox.currentNotification),
   ];
-  notificationBoxes[0].currentNotification.close();
+  gNotificationBox.currentNotification.close();
   await Promise.all(closeAlertPromises);
 
   // Close the second window we opened.
   await BrowserTestUtils.closeWindow(otherWindow);
 
   // Check that we are clear to upload and that the policy data us saved.
   Assert.ok(TelemetryReportingPolicy.canUpload(), "User should be allowed to upload now.");
   Assert.equal(TelemetryReportingPolicy.testIsUserNotified(), true,
--- a/browser/base/content/test/general/browser_storagePressure_notification.js
+++ b/browser/base/content/test/general/browser_storagePressure_notification.js
@@ -23,43 +23,41 @@ function openAboutPrefPromise() {
 // Test only displaying notification once within the given interval
 add_task(async function() {
   const TEST_NOTIFICATION_INTERVAL_MS = 2000;
   await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.pressureNotification.minIntervalMS", TEST_NOTIFICATION_INTERVAL_MS]]});
   // Commenting this to see if we really need it
   // await SpecialPowers.pushPrefEnv({set: [["privacy.reduceTimerPrecision", false]]});
 
   await notifyStoragePressure();
-  let notificationbox = document.getElementById("high-priority-global-notificationbox");
-  let notification = notificationbox.getNotificationWithValue("storage-pressure-notification");
+  let notification = gHighPriorityNotificationBox.getNotificationWithValue("storage-pressure-notification");
   ok(notification instanceof XULElement, "Should display storage pressure notification");
   notification.close();
 
   await notifyStoragePressure();
-  notification = notificationbox.getNotificationWithValue("storage-pressure-notification");
+  notification = gHighPriorityNotificationBox.getNotificationWithValue("storage-pressure-notification");
   is(notification, null, "Should not display storage pressure notification more than once within the given interval");
 
   await new Promise(resolve => setTimeout(resolve, TEST_NOTIFICATION_INTERVAL_MS + 1));
   await notifyStoragePressure();
-  notification = notificationbox.getNotificationWithValue("storage-pressure-notification");
+  notification = gHighPriorityNotificationBox.getNotificationWithValue("storage-pressure-notification");
   ok(notification instanceof XULElement, "Should display storage pressure notification after the given interval");
   notification.close();
 });
 
 // Test guiding user to the about:preferences when usage exceeds the given threshold
 add_task(async function() {
   await SpecialPowers.pushPrefEnv({ set: [["browser.storageManager.pressureNotification.minIntervalMS", 0]] });
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "https://example.com");
 
   const BYTES_IN_GIGABYTE = 1073741824;
   const USAGE_THRESHOLD_BYTES = BYTES_IN_GIGABYTE *
     Services.prefs.getIntPref("browser.storageManager.pressureNotification.usageThresholdGB");
   await notifyStoragePressure(USAGE_THRESHOLD_BYTES);
-  let notificationbox = document.getElementById("high-priority-global-notificationbox");
-  let notification = notificationbox.getNotificationWithValue("storage-pressure-notification");
+  let notification = gHighPriorityNotificationBox.getNotificationWithValue("storage-pressure-notification");
   ok(notification instanceof XULElement, "Should display storage pressure notification");
 
   let prefBtn = notification.getElementsByTagName("button")[1];
   let aboutPrefPromise = openAboutPrefPromise();
   prefBtn.doCommand();
   await aboutPrefPromise;
   let aboutPrefTab = gBrowser.selectedTab;
   let prefDoc = gBrowser.selectedBrowser.contentDocument;
@@ -71,19 +69,18 @@ add_task(async function() {
 
 // Test not displaying the 2nd notification if one is already being displayed
 add_task(async function() {
   const TEST_NOTIFICATION_INTERVAL_MS = 0;
   await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.pressureNotification.minIntervalMS", TEST_NOTIFICATION_INTERVAL_MS]]});
 
   await notifyStoragePressure();
   await notifyStoragePressure();
-  let notificationbox = document.getElementById("high-priority-global-notificationbox");
-  let allNotifications = notificationbox.allNotifications;
+  let allNotifications = gHighPriorityNotificationBox.allNotifications;
   let pressureNotificationCount = 0;
   allNotifications.forEach(notification => {
     if (notification.getAttribute("value") == "storage-pressure-notification") {
       pressureNotificationCount++;
     }
   });
   is(pressureNotificationCount, 1, "Should not display the 2nd notification when there is already one");
-  notificationbox.removeAllNotifications();
+  gHighPriorityNotificationBox.removeAllNotifications();
 });
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -26,26 +26,24 @@ function waitForNotificationClose(notifi
         cb();
       }
     }
   });
   observer.observe(parent, {childList: true});
 }
 
 function closeAllNotifications() {
-  let notificationBox = document.getElementById("global-notificationbox");
-
-  if (!notificationBox || !notificationBox.currentNotification) {
+  if (!gNotificationBox.currentNotification) {
     return Promise.resolve();
   }
 
   return new Promise(resolve => {
-    for (let notification of notificationBox.allNotifications) {
+    for (let notification of gNotificationBox.allNotifications) {
       waitForNotificationClose(notification, function() {
-        if (notificationBox.allNotifications.length === 0) {
+        if (gNotificationBox.allNotifications.length === 0) {
           resolve();
         }
       });
       notification.close();
     }
 
   });
 }
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -1201,20 +1201,19 @@ BrowserGlue.prototype = {
         label:     win.gNavigatorBundle.getString("slowStartup.disableNotificationButton.label"),
         accessKey: win.gNavigatorBundle.getString("slowStartup.disableNotificationButton.accesskey"),
         callback() {
           Services.prefs.setBoolPref("browser.slowStartup.notificationDisabled", true);
         },
       },
     ];
 
-    let nb = win.document.getElementById("global-notificationbox");
-    nb.appendNotification(message, "slow-startup",
-                          "chrome://browser/skin/slowStartup-16.png",
-                          nb.PRIORITY_INFO_LOW, buttons);
+    win.gNotificationBox.appendNotification(message, "slow-startup",
+      "chrome://browser/skin/slowStartup-16.png",
+      win.gNotificationBox.PRIORITY_INFO_LOW, buttons);
   },
 
   /**
    * Show a notification bar offering a reset.
    *
    * @param reason
    *        String of either "unused" or "uninstall", specifying the reason
    *        why a profile reset is offered.
@@ -1245,20 +1244,19 @@ BrowserGlue.prototype = {
         label:     resetBundle.formatStringFromName("refreshProfile.resetButton.label", [productName], 1),
         accessKey: resetBundle.GetStringFromName("refreshProfile.resetButton.accesskey"),
         callback() {
           ResetProfile.openConfirmationDialog(win);
         },
       },
     ];
 
-    let nb = win.document.getElementById("global-notificationbox");
-    nb.appendNotification(message, "reset-profile-notification",
-                          "chrome://global/skin/icons/question-16.png",
-                          nb.PRIORITY_INFO_LOW, buttons);
+    win.gNotificationBox.appendNotification(message, "reset-profile-notification",
+      "chrome://global/skin/icons/question-16.png",
+      win.gNotificationBox.PRIORITY_INFO_LOW, buttons);
   },
 
   _notifyUnsignedAddonsDisabled() {
     let win = BrowserWindowTracker.getTopWindow();
     if (!win)
       return;
 
     let message = win.gNavigatorBundle.getString("unsignedAddonsDisabled.message");
@@ -1267,19 +1265,19 @@ BrowserGlue.prototype = {
         label:     win.gNavigatorBundle.getString("unsignedAddonsDisabled.learnMore.label"),
         accessKey: win.gNavigatorBundle.getString("unsignedAddonsDisabled.learnMore.accesskey"),
         callback() {
           win.BrowserOpenAddonsMgr("addons://list/extension?unsigned=true");
         },
       },
     ];
 
-    let nb = win.document.getElementById("high-priority-global-notificationbox");
-    nb.appendNotification(message, "unsigned-addons-disabled", "",
-                          nb.PRIORITY_WARNING_MEDIUM, buttons);
+    win.gHighPriorityNotificationBox.appendNotification(message,
+      "unsigned-addons-disabled", "",
+      win.gHighPriorityNotificationBox.PRIORITY_WARNING_MEDIUM, buttons);
   },
 
   _firstWindowTelemetry(aWindow) {
     let scaling = aWindow.devicePixelRatio * 100;
     try {
       Services.telemetry.getHistogramById("DISPLAY_SCALING").add(scaling);
     } catch (ex) {}
   },
@@ -1830,32 +1828,31 @@ BrowserGlue.prototype = {
       let url = getNotifyString({propName: "notificationURL",
                                  prefName: "startup.homepage_override_url"});
       let label = getNotifyString({propName: "notificationButtonLabel",
                                    stringName: "pu.notifyButton.label"});
       let key = getNotifyString({propName: "notificationButtonAccessKey",
                                  stringName: "pu.notifyButton.accesskey"});
 
       let win = BrowserWindowTracker.getTopWindow();
-      let notifyBox = win.document.getElementById("high-priority-global-notificationbox");
 
       let buttons = [
                       {
                         label,
                         accessKey: key,
                         popup:     null,
                         callback(aNotificationBar, aButton) {
                           win.openTrustedLinkIn(url, "tab");
                         },
                       },
                     ];
 
-      notifyBox.appendNotification(text, "post-update-notification",
-                                   null, notifyBox.PRIORITY_INFO_LOW,
-                                   buttons);
+      win.gHighPriorityNotificationBox.appendNotification(text,
+        "post-update-notification", null,
+        win.gHighPriorityNotificationBox.PRIORITY_INFO_LOW, buttons);
     }
 
     if (!actions.includes("showAlert"))
       return;
 
     let title = getNotifyString({propName: "alertTitle",
                                  stringName: "puAlertTitle",
                                  stringParams: [appName]});
@@ -2924,19 +2921,19 @@ BrowserGlue.prototype = {
       getFormattedString("flashHang.message", [productName]);
     let buttons = [{
       label: win.gNavigatorBundle.getString("flashHang.helpButton.label"),
       accessKey: win.gNavigatorBundle.getString("flashHang.helpButton.accesskey"),
       callback() {
         win.openTrustedLinkIn("https://support.mozilla.org/kb/flash-protected-mode-autodisabled", "tab");
       },
     }];
-    let nb = win.document.getElementById("global-notificationbox");
-    nb.appendNotification(message, "flash-hang", null,
-                          nb.PRIORITY_INFO_MEDIUM, buttons);
+
+    win.gNotificationBox.appendNotification(message, "flash-hang", null,
+      win.gNotificationBox.PRIORITY_INFO_MEDIUM, buttons);
   },
 
   _updateFxaBadges() {
     let state = UIState.get();
     if (state.status == UIState.STATUS_LOGIN_FAILED ||
         state.status == UIState.STATUS_NOT_VERIFIED) {
       AppMenuNotifications.showBadgeOnlyNotification("fxa-needs-authentication");
     } else {
@@ -3184,18 +3181,16 @@ var DefaultBrowserCheck = {
       let optionsKey = shellBundle.getString("setDefaultBrowserOptions.accesskey");
 
       let neverLabel = shellBundle.getString("setDefaultBrowserNever.label");
       let neverKey = shellBundle.getString("setDefaultBrowserNever.accesskey");
 
       let yesButtonKey = shellBundle.getString("setDefaultBrowserConfirm.accesskey");
       let notNowButtonKey = shellBundle.getString("setDefaultBrowserNotNow.accesskey");
 
-      let notificationBox = win.document.getElementById("high-priority-global-notificationbox");
-
       this._createPopup(win, {
         label: notNowButton,
         accesskey: notNowButtonKey,
       }, {
         label: neverLabel,
         accesskey: neverKey,
       });
 
@@ -3212,21 +3207,20 @@ var DefaultBrowserCheck = {
           label: optionsMessage,
           accessKey: optionsKey,
           popup: this.OPTIONPOPUP,
         },
       ];
 
       let iconPixels = win.devicePixelRatio > 1 ? "32" : "16";
       let iconURL = "chrome://branding/content/icon" + iconPixels + ".png";
-      const priority = notificationBox.PRIORITY_WARNING_HIGH;
+      const priority = win.gHighPriorityNotificationBox.PRIORITY_WARNING_HIGH;
       let callback = this._onNotificationEvent.bind(this);
-      this._notification = notificationBox.appendNotification(promptMessage, "default-browser",
-                                                              iconURL, priority, buttons,
-                                                              callback);
+      this._notification = win.gHighPriorityNotificationBox.appendNotification(
+        promptMessage, "default-browser", iconURL, priority, buttons, callback);
     } else {
       // Modal prompt
       let promptTitle = shellBundle.getString("setDefaultBrowserTitle");
       let promptMessage = shellBundle.getFormattedString("setDefaultBrowserMessage",
                                                          [brandShortName]);
       let askLabel = shellBundle.getFormattedString("setDefaultBrowserDontAsk",
                                                     [brandShortName]);
 
--- a/browser/components/tests/browser/browser_bug538331.js
+++ b/browser/components/tests/browser/browser_bug538331.js
@@ -289,18 +289,16 @@ const BG_NOTIFY_TESTS = [
     notificationButtonLabel: "button label",
     notificationButtonAccessKey: "b",
   },
 ];
 
 // Test showing a notification after an update
 // _showUpdateNotification in nsBrowserGlue.js
 function testShowNotification() {
-  let notifyBox = document.getElementById("high-priority-global-notificationbox");
-
   // Catches any windows opened by these tests (e.g. alert windows) and closes
   // them
   gWindowCatcher.start();
 
   for (let i = 0; i < BG_NOTIFY_TESTS.length; i++) {
     let testCase = BG_NOTIFY_TESTS[i];
     ok(true, "Test showNotification " + (i + 1) + ": " + testCase.description);
 
@@ -323,17 +321,18 @@ function testShowNotification() {
       writeUpdatesToXMLFile(XML_EMPTY);
     }
 
     reloadUpdateManagerData();
     Services.prefs.setBoolPref(PREF_POSTUPDATE, true);
 
     gBG.observe(null, "browser-glue-test", "post-update-notification");
 
-    let updateBox = notifyBox.getNotificationWithValue("post-update-notification");
+    let updateBox = gHighPriorityNotificationBox.getNotificationWithValue(
+                                                    "post-update-notification");
     if (testCase.actions && testCase.actions.includes("showNotification") &&
         !testCase.actions.includes("silent")) {
       ok(updateBox, "Update notification box should have been displayed");
       if (updateBox) {
         if (testCase.notificationText) {
           is(updateBox.label, testCase.notificationText, "Update notification box " +
              "should have the label provided by the update");
         }
@@ -352,17 +351,17 @@ function testShowNotification() {
         // is correct.
         if (i == (BG_NOTIFY_TESTS.length - 1)) {
           // Wait for any windows caught by the windowcatcher to close
           gWindowCatcher.finish(function() {
             BrowserTestUtils.waitForNewTab(gBrowser).then(testNotificationURL);
             button.click();
           });
         } else {
-          notifyBox.removeAllNotifications(true);
+          gHighPriorityNotificationBox.removeAllNotifications(true);
         }
       } else if (i == (BG_NOTIFY_TESTS.length - 1)) {
         // If updateBox is null the test has already reported errors so bail
         finish_test();
       }
     } else {
       ok(!updateBox, "Update notification box should not have been displayed");
     }
--- a/browser/modules/ContentCrashHandlers.jsm
+++ b/browser/modules/ContentCrashHandlers.jsm
@@ -862,18 +862,18 @@ var UnsubmittedCrashHandler = {
     let chromeWin = BrowserWindowTracker.getTopWindow();
     if (!chromeWin) {
       // Can't show a notification in this case. We'll hopefully
       // get another opportunity to have the user submit their
       // crash reports later.
       return null;
     }
 
-    let nb =  chromeWin.document.getElementById("global-notificationbox");
-    let notification = nb.getNotificationWithValue(notificationID);
+    let notification = chromeWin.gNotificationBox
+                                .getNotificationWithValue(notificationID);
     if (notification) {
       return null;
     }
 
     let buttons = [{
       label: gNavigatorBundle.GetStringFromName("pendingCrashReports.send"),
       callback: () => {
         this.submitReports(reportIDs);
@@ -910,20 +910,19 @@ var UnsubmittedCrashHandler = {
           CrashSubmit.ignore(reportID);
         });
         if (onAction) {
           onAction();
         }
       }
     };
 
-    return nb.appendNotification(message, notificationID,
-                                 "chrome://browser/skin/tab-crashed.svg",
-                                 nb.PRIORITY_INFO_HIGH, buttons,
-                                 eventCallback);
+    return chromeWin.gNotificationBox.appendNotification(message,
+      notificationID, "chrome://browser/skin/tab-crashed.svg",
+      chromeWin.gNotificationBox.PRIORITY_INFO_HIGH, buttons, eventCallback);
   },
 
   get autoSubmit() {
     return Services.prefs
                    .getBoolPref("browser.crashReports.unsubmittedCheck.autoSubmit2");
   },
 
   set autoSubmit(val) {
--- a/browser/modules/ProcessHangMonitor.jsm
+++ b/browser/modules/ProcessHangMonitor.jsm
@@ -415,18 +415,18 @@ var ProcessHangMonitor = {
       this.hideNotification(win);
     }
   },
 
   /**
    * Show the notification for a hang.
    */
   showNotification(win, report) {
-    let nb = win.document.getElementById("high-priority-global-notificationbox");
-    let notification = nb.getNotificationWithValue("process-hang");
+    let notification =
+        win.gHighPriorityNotificationBox.getNotificationWithValue("process-hang");
     if (notification) {
       return;
     }
 
     let bundle = win.gNavigatorBundle;
 
     let buttons = [{
         label: bundle.getString("processHang.button_stop.label"),
@@ -482,29 +482,29 @@ var ProcessHangMonitor = {
         label: bundle.getString("processHang.button_debug.label"),
         accessKey: bundle.getString("processHang.button_debug.accessKey"),
         callback() {
           ProcessHangMonitor.debugScript(win);
         },
       });
     }
 
-    nb.appendNotification(message, "process-hang",
-                          "chrome://browser/content/aboutRobots-icon.png",
-                          nb.PRIORITY_WARNING_HIGH, buttons);
+    win.gHighPriorityNotificationBox.appendNotification(message, "process-hang",
+      "chrome://browser/content/aboutRobots-icon.png",
+      win.gHighPriorityNotificationBox.PRIORITY_WARNING_HIGH, buttons);
   },
 
   /**
    * Ensure that no hang notifications are visible in |win|.
    */
   hideNotification(win) {
-    let nb = win.document.getElementById("high-priority-global-notificationbox");
-    let notification = nb.getNotificationWithValue("process-hang");
+    let notification =
+        win.gHighPriorityNotificationBox.getNotificationWithValue("process-hang");
     if (notification) {
-      nb.removeNotification(notification);
+      win.gHighPriorityNotificationBox.removeNotification(notification);
     }
   },
 
   /**
    * Install event handlers on |win| to watch for events that would
    * cause a different hang report to be displayed.
    */
   trackWindow(win) {
--- a/browser/modules/test/browser/browser_ProcessHangNotifications.js
+++ b/browser/modules/test/browser/browser_ProcessHangNotifications.js
@@ -1,25 +1,21 @@
 /* globals ProcessHangMonitor */
 
 const { WebExtensionPolicy } =
   Cu.getGlobalForObject(ChromeUtils.import("resource://gre/modules/Services.jsm", {}));
 
 ChromeUtils.import("resource://gre/modules/UpdateUtils.jsm");
 
-function getNotificationBox(aWindow) {
-  return aWindow.document.getElementById("high-priority-global-notificationbox");
-}
-
 function promiseNotificationShown(aWindow, aName) {
   return new Promise((resolve) => {
-    let notification = getNotificationBox(aWindow);
-    notification.addEventListener("AlertActive", function() {
-      is(notification.allNotifications.length, 1, "Notification Displayed.");
-      resolve(notification);
+    let notificationBox = aWindow.gHighPriorityNotificationBox;
+    notificationBox.addEventListener("AlertActive", function() {
+      is(notificationBox.allNotifications.length, 1, "Notification Displayed.");
+      resolve(notificationBox);
     }, {once: true});
   });
 }
 
 function pushPrefs(...aPrefs) {
   return SpecialPowers.pushPrefEnv({"set": aPrefs});
 }
 
--- a/browser/modules/test/browser/browser_UnsubmittedCrashHandler.js
+++ b/browser/modules/test/browser/browser_UnsubmittedCrashHandler.js
@@ -164,29 +164,26 @@ function waitForIgnoredReports(reportIDs
   for (let reportID of reportIDs) {
     let file = dir.clone();
     file.append(reportID + ".dmp.ignore");
     promises.push(OS.File.exists(file.path));
   }
   return Promise.all(promises);
 }
 
-let gNotificationBox;
-
 add_task(async function setup() {
   // Pending crash reports are stored in the UAppData folder,
   // which exists outside of the profile folder. In order to
   // not overwrite / clear pending crash reports for the poor
   // soul who runs this test, we use AppData.jsm to point to
   // a special made-up directory inside the profile
   // directory.
   await makeFakeAppDir();
   // We'll assume that the notifications will be shown in the current
   // browser window's global notification box.
-  gNotificationBox = document.getElementById("global-notificationbox");
 
   // If we happen to already be seeing the unsent crash report
   // notification, it's because the developer running this test
   // happened to have some unsent reports in their UAppDir.
   // We'll remove the notification without touching those reports.
   let notification =
     gNotificationBox.getNotificationWithValue("pending-crash-reports");
   if (notification) {
@@ -234,17 +231,16 @@ add_task(async function setup() {
   await SpecialPowers.pushPrefEnv({
     set: [
       ["browser.crashReports.unsubmittedCheck.enabled", true],
     ],
   });
   UnsubmittedCrashHandler.init();
 
   registerCleanupFunction(function() {
-    gNotificationBox = null;
     clearPendingCrashReports();
     env.set("MOZ_CRASHREPORTER_URL", oldServerURL);
   });
 });
 
 /**
  * Tests that if there are no pending crash reports, then the
  * notification will not show up.
--- a/devtools/shared/fronts/csscoverage.js
+++ b/devtools/shared/fronts/csscoverage.js
@@ -39,17 +39,17 @@ const CSSUsageFront = protocol.FrontClas
     this.manage(this);
   },
 
   _onStateChange: protocol.preEvent("state-change", function(ev) {
     isRunning = ev.isRunning;
     ev.target = target;
 
     if (isRunning) {
-      const gnb = chromeWindow.document.getElementById("global-notificationbox");
+      const gnb = chromeWindow.gNotificationBox;
       notification = gnb.getNotificationWithValue("csscoverage-running");
 
       if (notification == null) {
         const notifyStop = reason => {
           if (reason == "removed") {
             this.stop();
           }
         };
--- a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
+++ b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
@@ -1579,20 +1579,18 @@ var BrowserTestUtils = {
    *        notification is expected to appear.
    * @param notificationValue (string)
    *        The "value" of the notification, which is often used as
    *        a unique identifier. Example: "captive-portal-detected".
    * @return Promise
    *        Resolves to the <xul:notification> that is being shown.
    */
   waitForGlobalNotificationBar(win, notificationValue) {
-    let notificationBox =
-      win.document.getElementById("high-priority-global-notificationbox");
-    return this.waitForNotificationInNotificationBox(notificationBox,
-                                                     notificationValue);
+    return this.waitForNotificationInNotificationBox(
+                       win.gHighPriorityNotificationBox, notificationValue);
   },
 
   waitForNotificationInNotificationBox(notificationBox, notificationValue) {
     return new Promise((resolve) => {
       let check = (event) => {
         return event.target.value == notificationValue;
       };
 
--- a/toolkit/components/normandy/lib/Heartbeat.jsm
+++ b/toolkit/components/normandy/lib/Heartbeat.jsm
@@ -147,17 +147,17 @@ var Heartbeat = class {
 
           // Return true so that the notification bar doesn't close itself since
           // we have a thank you message to show.
           return true;
         },
       }];
     }
 
-    this.notificationBox = this.chromeWindow.document.querySelector("#high-priority-global-notificationbox");
+    this.notificationBox = this.chromeWindow.gHighPriorityNotificationBox;
     this.notice = this.notificationBox.appendNotification(
       this.options.message,
       "heartbeat-" + this.options.flowId,
       "resource://normandy/skin/shared/heartbeat-icon.svg",
       this.notificationBox.PRIORITY_INFO_HIGH,
       this.buttons,
       eventType => {
         if (eventType !== "removed") {
--- a/toolkit/components/normandy/test/browser/browser_Heartbeat.js
+++ b/toolkit/components/normandy/test/browser/browser_Heartbeat.js
@@ -74,17 +74,17 @@ sandboxManager.addHold("test running");
 
 
 // Several of the behaviors of heartbeat prompt are mutually exclusive, so checks are broken up
 // into three batches.
 
 /* Batch #1 - General UI, Stars, and telemetry data */
 add_task(async function() {
   const targetWindow = Services.wm.getMostRecentWindow("navigator:browser");
-  const notificationBox = targetWindow.document.querySelector("#high-priority-global-notificationbox");
+  const notificationBox = targetWindow.gHighPriorityNotificationBox;
 
   const preCount = notificationBox.childElementCount;
   const hb = new Heartbeat(targetWindow, sandboxManager, {
     testing: true,
     flowId: "test",
     message: "test",
     engagementButtonLabel: undefined,
     learnMoreMessage: "Learn More",
@@ -123,17 +123,17 @@ add_task(async function() {
   await telemetrySentPromise;
   BrowserTestUtils.removeTab(tab);
 });
 
 
 // Batch #2 - Engagement buttons
 add_task(async function() {
   const targetWindow = Services.wm.getMostRecentWindow("navigator:browser");
-  const notificationBox = targetWindow.document.querySelector("#high-priority-global-notificationbox");
+  const notificationBox = targetWindow.gHighPriorityNotificationBox;
   const hb = new Heartbeat(targetWindow, sandboxManager, {
     testing: true,
     flowId: "test",
     message: "test",
     engagementButtonLabel: "Click me!",
     postAnswerUrl: "https://example.org/postAnswer",
     learnMoreMessage: "Learn More",
     learnMoreUrl: "https://example.org/learnMore",