Bug 1368364 - backout bug 1242505 as it causes browser/modules/ intermittent failures. r=paolo
authorJoel Maher <jmaher@mozilla.com>
Sat, 03 Jun 2017 10:34:14 +0200
changeset 410300 90df8b3f52d60d79b2730153f97300039019b694
parent 410299 43af422173e3bdfddc18c02d7f7c430d6ec9cdfe
child 410301 130efc657df7e7fe291cc42307f3eb3cb0484dfc
child 410320 908a9b9835446178c801ea908c8207d58bf8dce4
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspaolo
bugs1368364, 1242505
milestone55.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 1368364 - backout bug 1242505 as it causes browser/modules/ intermittent failures. r=paolo
browser/base/content/test/general/browser_aboutSupport_newtab_security_state.js
browser/base/content/test/general/browser_scope.js
browser/base/content/test/general/browser_tabs_owner.js
browser/base/content/test/siteIdentity/browser_no_mcb_for_loopback.js
browser/base/content/test/social/browser_social_activation.js
browser/base/content/test/sync/browser_aboutAccounts.js
browser/base/content/test/webrtc/browser_devices_get_user_media_screen.js
browser/components/extensions/ExtensionPopups.jsm
browser/components/extensions/test/browser/browser_ext_tabs_executeScript_bad.js
browser/components/extensions/test/browser/head.js
browser/components/sessionstore/SessionStore.jsm
browser/components/sessionstore/test/browser_354894_perwindowpb.js
browser/extensions/shield-recipe-client/lib/PreferenceExperiments.jsm
browser/modules/ContentCrashHandlers.jsm
devtools/client/debugger/new/test/mochitest/.eslintrc
devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-01.js
devtools/client/debugger/test/mochitest/browser_dbg_promises-rejection-stack.js
devtools/client/debugger/test/mochitest/browser_dbg_terminate-on-tab-close.js
devtools/client/debugger/test/mochitest/browser_dbg_worker-console-04.js
devtools/client/debugger/test/mochitest/browser_dbg_worker-window.js
devtools/client/framework/test/browser_devtools_api.js
devtools/client/framework/test/browser_toolbox_tool_ready.js
devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js
devtools/client/framework/test/shared-head.js
devtools/client/inspector/computed/test/browser_computed_style-editor-link.js
devtools/client/inspector/markup/test/browser_markup_links_06.js
devtools/client/inspector/rules/test/browser_rules_style-editor-link.js
devtools/client/inspector/test/browser_inspector_highlighter-comments.js
devtools/client/netmonitor/test/browser_net_simple-request-data.js
devtools/client/projecteditor/test/browser_projecteditor_editing_01.js
devtools/client/projecteditor/test/browser_projecteditor_editors_image.js
devtools/client/projecteditor/test/browser_projecteditor_immediate_destroy.js
devtools/client/projecteditor/test/browser_projecteditor_saveall.js
devtools/client/projecteditor/test/browser_projecteditor_tree_selection_02.js
devtools/client/projecteditor/test/head.js
devtools/client/responsivedesign/test/browser_responsive_cmd.js
devtools/client/shared/test/browser_telemetry_toolboxtabs_shadereditor.js
devtools/client/shared/test/browser_toolbar_tooltip.js
devtools/client/webaudioeditor/test/browser_wa_first-run.js
devtools/client/webaudioeditor/test/browser_wa_reset-01.js
devtools/client/webaudioeditor/test/browser_wa_reset-04.js
devtools/client/webaudioeditor/test/head.js
devtools/client/webconsole/test/browser_webconsole_output_01.js
devtools/client/webconsole/test/browser_webconsole_output_04.js
devtools/client/webconsole/test/browser_webconsole_output_dom_elements_01.js
devtools/client/webconsole/test/browser_webconsole_output_events.js
devtools/server/actors/webextension-inspected-window.js
dom/base/test/browser_timeout_throttling_with_audio_playback.js
dom/tests/browser/helper_largeAllocation.js
testing/mochitest/browser-test.js
testing/mochitest/tests/browser/browser.ini
testing/mochitest/tests/browser/browser_fail_add_task_uncaught_rejection.js
testing/mochitest/tests/browser/browser_fail_uncaught_rejection.js
testing/mochitest/tests/browser/browser_fail_uncaught_rejection_expected.js
testing/mochitest/tests/browser/browser_fail_uncaught_rejection_expected_multi.js
testing/mochitest/tests/browser/browser_uncaught_rejection_expected.js
toolkit/components/startup/tests/browser/browser_bug537449.js
toolkit/content/tests/browser/browser_block_webAudio.js
toolkit/content/tests/browser/browser_mute_webAudio.js
toolkit/modules/tests/modules/PromiseTestUtils.jsm
toolkit/mozapps/extensions/test/browser/browser_bug570760.js
toolkit/mozapps/extensions/test/xpinstall/browser_auth3.js
toolkit/mozapps/extensions/test/xpinstall/browser_auth4.js
tools/lint/eslint/eslint-plugin-mozilla/lib/configs/browser-test.js
--- a/browser/base/content/test/general/browser_aboutSupport_newtab_security_state.js
+++ b/browser/base/content/test/general/browser_aboutSupport_newtab_security_state.js
@@ -1,11 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: window.location is null");
+
+
 add_task(async function checkIdentityOfAboutSupport() {
   let tab = gBrowser.loadOneTab("about:support", {
     referrerURI: null,
     inBackground: false,
     allowThirdPartyFixup: false,
     relatedToCurrent: false,
     skipAnimation: true,
     allowMixedContent: false,
--- a/browser/base/content/test/general/browser_scope.js
+++ b/browser/base/content/test/general/browser_scope.js
@@ -1,4 +1,10 @@
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.docShell is null");
+
 function test() {
   ok(!!gBrowser, "gBrowser exists");
   is(gBrowser, getBrowser(), "both ways of getting tabbrowser work");
 }
--- a/browser/base/content/test/general/browser_tabs_owner.js
+++ b/browser/base/content/test/general/browser_tabs_owner.js
@@ -1,8 +1,20 @@
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: gBrowser._finalizeTabSwitch is not a function");
+
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: gBrowser._finalizeTabSwitch is not a function");
+
 function test() {
   BrowserTestUtils.addTab(gBrowser);
   BrowserTestUtils.addTab(gBrowser);
   BrowserTestUtils.addTab(gBrowser);
 
   var tabs = gBrowser.tabs;
   var owner;
 
--- a/browser/base/content/test/siteIdentity/browser_no_mcb_for_loopback.js
+++ b/browser/base/content/test/siteIdentity/browser_no_mcb_for_loopback.js
@@ -3,24 +3,16 @@
 
 // The test loads a HTTPS web page with active content from HTTP loopback URLs
 // and makes sure that the mixed content flags on the docshell are not set.
 //
 // Note that the URLs referenced within the test page intentionally use the
 // unassigned port 8 because we don't want to actually load anything, we just
 // want to check that the URLs are not blocked.
 
-// The following rejections should not be left uncaught. This test has been
-// whitelisted until the issue is fixed.
-if (!gMultiProcessBrowser) {
-  Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
-  PromiseTestUtils.expectUncaughtRejection(/NetworkError/);
-  PromiseTestUtils.expectUncaughtRejection(/NetworkError/);
-}
-
 const TEST_URL = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com") + "test_no_mcb_for_loopback.html";
 
 const LOOPBACK_PNG_URL = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://127.0.0.1:8888") + "moz.png";
 
 const PREF_BLOCK_DISPLAY = "security.mixed_content.block_display_content";
 const PREF_BLOCK_ACTIVE = "security.mixed_content.block_active_content";
 
 registerCleanupFunction(function() {
--- a/browser/base/content/test/social/browser_social_activation.js
+++ b/browser/base/content/test/social/browser_social_activation.js
@@ -1,12 +1,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: Assert is null");
+
+
 var SocialService = Cu.import("resource:///modules/SocialService.jsm", {}).SocialService;
 
 var tabsToRemove = [];
 
 function removeProvider(provider) {
   return new Promise(resolve => {
     // a full install sets the manifest into a pref, addProvider alone doesn't,
     // make sure we uninstall if the manifest was added.
--- a/browser/base/content/test/sync/browser_aboutAccounts.js
+++ b/browser/base/content/test/sync/browser_aboutAccounts.js
@@ -1,12 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: window.location is null");
+
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
   "resource://gre/modules/Promise.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
   "resource://gre/modules/FxAccounts.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
   "resource://gre/modules/FileUtils.jsm");
 
 const CHROME_BASE = "chrome://mochitests/content/browser/browser/base/content/test/sync/";
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media_screen.js
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_screen.js
@@ -1,21 +1,12 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-// The rejection "The fetching process for the media resource was aborted by the
-// user agent at the user's request." is left unhandled in some cases. This bug
-// should be fixed, but for the moment this file is whitelisted.
-//
-// NOTE: Whitelisting a class of rejections should be limited. Normally you
-//       should use "expectUncaughtRejection" to flag individual failures.
-Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
-PromiseTestUtils.whitelistRejectionsGlobally(/aborted by the user agent/);
-
 const permissionError = "error: NotAllowedError: The request is not allowed " +
     "by the user agent or the platform in the current context.";
 
 const notFoundError =
     "error: NotFoundError: The object can not be found here.";
 
 var gTests = [
 
--- a/browser/components/extensions/ExtensionPopups.jsm
+++ b/browser/components/extensions/ExtensionPopups.jsm
@@ -103,18 +103,16 @@ class BasePopup {
     this.closePopup();
   }
 
   destroy() {
     this.extension.forgetOnClose(this);
 
     this.destroyed = true;
     this.browserLoadedDeferred.reject(new Error("Popup destroyed"));
-    // Ignore unhandled rejections if the "attach" method is not called.
-    this.browserLoaded.catch(() => {});
 
     BasePopup.instances.get(this.window).delete(this.extension);
 
     return this.browserReady.then(() => {
       if (this.browser) {
         this.destroyBrowser(this.browser, true);
         this.browser.remove();
       }
--- a/browser/components/extensions/test/browser/browser_ext_tabs_executeScript_bad.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_executeScript_bad.js
@@ -1,19 +1,10 @@
 "use strict";
 
-// Various "Missing host permission" rejections are left uncaught. This may be
-// caused by issues in the test, in the testing framework, or in production
-// code. This bug should be fixed, but for the moment this file is whitelisted.
-//
-// NOTE: Whitelisting a class of rejections should be limited. Normally you
-//       should use "expectUncaughtRejection" to flag individual failures.
-Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
-PromiseTestUtils.whitelistRejectionsGlobally(/Missing host permission/);
-
 // This is a pretty terrible hack, but it's the best we can do until we
 // support |executeScript| callbacks and |lastError|.
 async function testHasNoPermission(params) {
   let contentSetup = params.contentSetup || (() => Promise.resolve());
 
   async function background(contentSetup) {
     browser.runtime.onMessage.addListener((msg, sender) => {
       browser.test.assertEq(msg, "second script ran", "second script ran");
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -16,26 +16,16 @@
  *          imageBuffer imageBufferFromDataURI
  *          getListStyleImage getPanelForNode
  *          awaitExtensionPanel awaitPopupResize
  *          promiseContentDimensions alterContent
  *          promisePrefChangeObserved openContextMenuInFrame
  *          promiseAnimationFrame
  */
 
-// There are shutdown issues for which multiple rejections are left uncaught.
-// This bug should be fixed, but for the moment this directory is whitelisted.
-//
-// NOTE: Entire directory whitelisting should be kept to a minimum. Normally you
-//       should use "expectUncaughtRejection" to flag individual failures.
-const {PromiseTestUtils} = Cu.import("resource://testing-common/PromiseTestUtils.jsm", {});
-PromiseTestUtils.whitelistRejectionsGlobally(/Message manager disconnected/);
-PromiseTestUtils.whitelistRejectionsGlobally(/No matching message handler/);
-PromiseTestUtils.whitelistRejectionsGlobally(/Receiving end does not exist/);
-
 const {AppConstants} = Cu.import("resource://gre/modules/AppConstants.jsm", {});
 const {CustomizableUI} = Cu.import("resource:///modules/CustomizableUI.jsm", {});
 
 // We run tests under two different configurations, from browser.ini and
 // browser-remote.ini. When running from browser-remote.ini, the tests are
 // copied to the sub-directory "test-oop-extensions", which we detect here, and
 // use to select our configuration.
 if (gTestPath.includes("test-oop-extensions")) {
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -1305,17 +1305,17 @@ var SessionStoreInternal = {
         }
         TelemetryStopwatch.start("FX_SESSION_RESTORE_STARTUP_ONLOAD_INITIAL_WINDOW_MS");
         this.initializeWindow(aWindow, initialState);
         TelemetryStopwatch.finish("FX_SESSION_RESTORE_STARTUP_ONLOAD_INITIAL_WINDOW_MS");
 
         // Let everyone know we're done.
         this._deferredInitialized.resolve();
       }
-    }).catch(console.error);
+    }, console.error);
   },
 
   /**
    * On window close...
    * - remove event listeners from tabs
    * - save all window data
    * @param aWindow
    *        Window reference
--- a/browser/components/sessionstore/test/browser_354894_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_354894_perwindowpb.js
@@ -19,25 +19,16 @@
  * not enabled on that platform (platform shim; the application is kept running
  * although there are no windows left)
  * @note There is a difference when closing a browser window with
  * BrowserTryToCloseWindow() as opposed to close(). The former will make
  * nsSessionStore restore a window next time it gets a chance and will post
  * notifications. The latter won't.
  */
 
-// The rejection "RecentWindow.getMostRecentBrowserWindow(...) is null" is left
-// unhandled in some cases. This bug should be fixed, but for the moment this
-// file is whitelisted.
-//
-// NOTE: Whitelisting a class of rejections should be limited. Normally you
-//       should use "expectUncaughtRejection" to flag individual failures.
-Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
-PromiseTestUtils.whitelistRejectionsGlobally(/getMostRecentBrowserWindow/);
-
 // Some urls that might be opened in tabs and/or popups
 // Do not use about:blank:
 // That one is reserved for special purposes in the tests
 const TEST_URLS = ["about:mozilla", "about:buildconfig"];
 
 // Number of -request notifications to except
 // remember to adjust when adding new tests
 const NOTIFICATIONS_EXPECTED = 6;
--- a/browser/extensions/shield-recipe-client/lib/PreferenceExperiments.jsm
+++ b/browser/extensions/shield-recipe-client/lib/PreferenceExperiments.jsm
@@ -250,18 +250,17 @@ this.PreferenceExperiments = {
         `An observer for the preference experiment ${experimentName} is already active.`
       );
     }
 
     const observerInfo = {
       preferenceName,
       observer(newValue) {
         if (newValue !== preferenceValue) {
-          PreferenceExperiments.stop(experimentName, false)
-                               .catch(Cu.reportError);
+          PreferenceExperiments.stop(experimentName, false);
         }
       },
     };
     experimentObservers.set(experimentName, observerInfo);
     Preferences.observe(preferenceName, observerInfo.observer);
   },
 
   /**
--- a/browser/modules/ContentCrashHandlers.jsm
+++ b/browser/modules/ContentCrashHandlers.jsm
@@ -378,17 +378,17 @@ this.TabCrashHandler = {
     // with the empty string.
     if (!includeURL) {
       extraExtraKeyVals["URL"] = "";
     }
 
     CrashSubmit.submit(dumpID, {
       recordSubmission: true,
       extraExtraKeyVals,
-    }).catch(Cu.reportError);
+    }).then(null, Cu.reportError);
 
     this.prefs.setBoolPref("sendReport", true);
     this.prefs.setBoolPref("includeURL", includeURL);
     this.prefs.setBoolPref("emailMe", emailMe);
     if (emailMe) {
       this.prefs.setCharPref("email", email);
     } else {
       this.prefs.setCharPref("email", "");
@@ -876,17 +876,17 @@ this.UnsubmittedCrashHandler = {
    *        The array of reportIDs to submit.
    */
   submitReports(reportIDs) {
     for (let reportID of reportIDs) {
       CrashSubmit.submit(reportID, {
         extraExtraKeyVals: {
           "SubmittedFromInfobar": true,
         },
-      }).catch(Cu.reportError);
+      });
     }
   },
 };
 
 this.PluginCrashReporter = {
   /**
    * Makes the PluginCrashReporter ready to hear about and
    * submit crash reports.
@@ -990,17 +990,17 @@ this.PluginCrashReporter = {
     let { pluginDumpID, browserDumpID } = this.crashReports.get(runID);
 
     let submissionPromise = CrashSubmit.submit(pluginDumpID, {
       recordSubmission: true,
       extraExtraKeyVals: keyVals,
     });
 
     if (browserDumpID)
-      CrashSubmit.submit(browserDumpID).catch(Cu.reportError);
+      CrashSubmit.submit(browserDumpID);
 
     this.broadcastState(runID, "submitting");
 
     submissionPromise.then(() => {
       this.broadcastState(runID, "success");
     }, () => {
       this.broadcastState(runID, "failed");
     });
--- a/devtools/client/debugger/new/test/mochitest/.eslintrc
+++ b/devtools/client/debugger/new/test/mochitest/.eslintrc
@@ -21,16 +21,17 @@
     "is": false,
     "isnot": false,
     "ok": false,
     "registerCleanupFunction": false,
     "requestLongerTimeout": false,
     "SimpleTest": false,
     "SpecialPowers": false,
     "TestUtils": false,
+    "thisTestLeaksUncaughtRejectionsAndShouldBeFixed": false,
     "todo": false,
     "todo_is": false,
     "todo_isnot": false,
     "waitForClipboard": false,
     "waitForExplicitFinish": false,
     "waitForFocus": false,
 
     // Globals introduced in debugger-specific head.js
--- a/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-01.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_break-on-dom-01.js
@@ -1,13 +1,19 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejections should be fixed.
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("[object Object]");
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed(
+  "TypeError: this.transport is null");
+
 /**
  * Tests that event listeners aren't fetched when the events tab isn't selected.
  */
 
 const TAB_URL = EXAMPLE_URL + "doc_event-listeners-02.html";
 
 function test() {
   let options = {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_promises-rejection-stack.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_promises-rejection-stack.js
@@ -8,23 +8,16 @@
  */
 
 "use strict";
 
 const TAB_URL = EXAMPLE_URL + "doc_promise-get-rejection-stack.html";
 const { PromisesFront } = require("devtools/shared/fronts/promises");
 var events = require("sdk/event/core");
 
-// The code in the document above leaves an uncaught rejection. This is only
-// reported to the testing framework if the code is loaded in the main process.
-if (!gMultiProcessBrowser) {
-  Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
-  PromiseTestUtils.expectUncaughtRejection(/hello/);
-}
-
 const TEST_DATA = [
   {
     functionDisplayName: "returnPromise/<",
     line: 19,
     column: 47
   },
   {
     functionDisplayName: "returnPromise",
--- a/devtools/client/debugger/test/mochitest/browser_dbg_terminate-on-tab-close.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_terminate-on-tab-close.js
@@ -1,24 +1,21 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejections should be fixed.
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("[object Object]");
+
 /**
  * Tests that debuggee scripts are terminated on tab closure.
  */
 
-// The following rejection should not be left uncaught. This test has been
-// whitelisted until the issue is fixed.
-if (!gMultiProcessBrowser) {
-  Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
-  PromiseTestUtils.expectUncaughtRejection(/error\.message is undefined/);
-}
-
 const TAB_URL = EXAMPLE_URL + "doc_terminate-on-tab-close.html";
 
 function test() {
   let options = {
     source: TAB_URL,
     line: 1
   };
   initDebugger(TAB_URL, options).then(([aTab,, aPanel]) => {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_worker-console-04.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_worker-console-04.js
@@ -1,20 +1,12 @@
 // Check that the date and regexp previewers work in the console of a worker debugger.
 
 "use strict";
 
-// The following intermittent rejection should not be left uncaught. This test
-// has been whitelisted until the issue is fixed.
-//
-// NOTE: Whitelisting a class of rejections should be limited. Normally you
-//       should use "expectUncaughtRejection" to flag individual failures.
-Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
-PromiseTestUtils.whitelistRejectionsGlobally(/[object Object]/);
-
 const TAB_URL = EXAMPLE_URL + "doc_WorkerActor.attachThread-tab.html";
 const WORKER_URL = "code_WorkerActor.attachThread-worker.js";
 
 add_task(function* testPausedByConsole() {
   let {client, tab, workerClient, toolbox} =
     yield initWorkerDebugger(TAB_URL, WORKER_URL);
 
   info("Check Date objects can be used in the console");
--- a/devtools/client/debugger/test/mochitest/browser_dbg_worker-window.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_worker-window.js
@@ -1,17 +1,16 @@
 // Check to make sure that a worker can be attached to a toolbox
 // directly, and that the toolbox has expected properties.
 
 "use strict";
 
-// The following "connectionClosed" rejection should not be left uncaught. This
-// test has been whitelisted until the issue is fixed.
-Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
-PromiseTestUtils.expectUncaughtRejection(/[object Object]/);
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejections should be fixed.
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("[object Object]");
 
 var TAB_URL = EXAMPLE_URL + "doc_WorkerActor.attachThread-tab.html";
 var WORKER_URL = "code_WorkerActor.attachThread-worker.js";
 
 add_task(function* () {
   yield pushPrefs(["devtools.scratchpad.enabled", true]);
 
   DebuggerServer.init();
--- a/devtools/client/framework/test/browser_devtools_api.js
+++ b/devtools/client/framework/test/browser_devtools_api.js
@@ -1,13 +1,22 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejections should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.docShell is null");
+
+// When running in a standalone directory, we get this error
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.doc is undefined");
+
 // Tests devtools API
 
 const toolId1 = "test-tool-1";
 const toolId2 = "test-tool-2";
 
 function test() {
   addTab("about:blank").then(runTests1);
 }
--- a/devtools/client/framework/test/browser_toolbox_tool_ready.js
+++ b/devtools/client/framework/test/browser_toolbox_tool_ready.js
@@ -2,16 +2,23 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 requestLongerTimeout(5);
 
+/**
+ * Whitelisting this test.
+ * As part of bug 1077403, the leaking uncaught rejection should be fixed.
+ */
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Shader Editor is " +
+  "still waiting for a WebGL context to be created.");
+
 function performChecks(target) {
   return Task.spawn(function* () {
     let toolIds = gDevTools.getToolDefinitionArray()
                            .filter(def => def.isTargetSupported(target))
                            .map(def => def.id);
 
     let toolbox;
     for (let index = 0; index < toolIds.length; index++) {
--- a/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js
+++ b/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js
@@ -1,15 +1,22 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+/**
+ * Whitelisting this test.
+ * As part of bug 1077403, the leaking uncaught rejection should be fixed.
+ */
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Shader Editor is " +
+  "still waiting for a WebGL context to be created.");
+
 const { DebuggerServer } = require("devtools/server/main");
 const { DebuggerClient } = require("devtools/shared/client/main");
 
 // Bug 1277805: Too slow for debug runs
 requestLongerTimeout(2);
 
 /**
  * Bug 979536: Ensure fronts are destroyed after toolbox close.
--- a/devtools/client/framework/test/shared-head.js
+++ b/devtools/client/framework/test/shared-head.js
@@ -14,32 +14,16 @@ const {classes: Cc, interfaces: Ci, util
   = Components;
 
 function scopedCuImport(path) {
   const scope = {};
   Cu.import(path, scope);
   return scope;
 }
 
-// There are shutdown issues for which multiple rejections are left uncaught.
-// This bug should be fixed, but for the moment devtools are whitelisted.
-//
-// NOTE: Entire directory whitelisting should be kept to a minimum. Normally you
-//       should use "expectUncaughtRejection" to flag individual failures.
-const {PromiseTestUtils} = scopedCuImport("resource://testing-common/PromiseTestUtils.jsm");
-PromiseTestUtils.whitelistRejectionsGlobally(/Component not initialized/);
-PromiseTestUtils.whitelistRejectionsGlobally(/Connection closed/);
-PromiseTestUtils.whitelistRejectionsGlobally(/destroy/);
-PromiseTestUtils.whitelistRejectionsGlobally(/is no longer, usable/);
-PromiseTestUtils.whitelistRejectionsGlobally(/this\._urls is null/);
-PromiseTestUtils.whitelistRejectionsGlobally(/this\.tabTarget is null/);
-PromiseTestUtils.whitelistRejectionsGlobally(/this\.toolbox is null/);
-PromiseTestUtils.whitelistRejectionsGlobally(/this\.webConsoleClient is null/);
-PromiseTestUtils.whitelistRejectionsGlobally(/this\.worker is null/);
-
 const {console} = scopedCuImport("resource://gre/modules/Console.jsm");
 const {ScratchpadManager} = scopedCuImport("resource://devtools/client/scratchpad/scratchpad-manager.jsm");
 const {loader, require} = scopedCuImport("resource://devtools/shared/Loader.jsm");
 
 const {gDevTools} = require("devtools/client/framework/devtools");
 const {TargetFactory} = require("devtools/client/framework/target");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const flags = require("devtools/shared/flags");
--- a/devtools/client/inspector/computed/test/browser_computed_style-editor-link.js
+++ b/devtools/client/inspector/computed/test/browser_computed_style-editor-link.js
@@ -1,14 +1,18 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Unknown sheet source");
+
 // Tests the links from the computed view to the style editor.
 
 const STYLESHEET_URL = "data:text/css," + encodeURIComponent(
   ".highlight {color: blue}");
 
 const DOCUMENT_URL = "data:text/html;charset=utf-8," + encodeURIComponent(
   `<html>
    <head>
--- a/devtools/client/inspector/markup/test/browser_markup_links_06.js
+++ b/devtools/client/inspector/markup/test/browser_markup_links_06.js
@@ -2,21 +2,16 @@
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Tests that the contextual menu items shown when clicking on linked attributes
 // for <script> and <link> tags actually open the right tools.
 
-// The following rejection should not be left uncaught. This test has been
-// whitelisted until the issue is fixed.
-Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
-PromiseTestUtils.expectUncaughtRejection(/NS_ERROR_NOT_INITIALIZED/);
-
 const TEST_URL = URL_ROOT + "doc_markup_links.html";
 
 add_task(function* () {
   let {toolbox, inspector} = yield openInspectorForURL(TEST_URL);
 
   info("Select a node with a cssresource attribute");
   yield selectNode("link", inspector);
 
--- a/devtools/client/inspector/rules/test/browser_rules_style-editor-link.js
+++ b/devtools/client/inspector/rules/test/browser_rules_style-editor-link.js
@@ -1,14 +1,18 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+// FIXME: Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Unknown sheet source");
+
 // Test the links from the rule-view to the styleeditor
 
 const STYLESHEET_URL = "data:text/css," + encodeURIComponent(
   ["#first {",
    "color: blue",
    "}"].join("\n"));
 
 const EXTERNAL_STYLESHEET_FILE_NAME = "doc_style_editor_link.css";
--- a/devtools/client/inspector/test/browser_inspector_highlighter-comments.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-comments.js
@@ -1,15 +1,21 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("false");
+
 // Test that hovering over the markup-view's containers doesn't always show the
 // highlighter, depending on the type of node hovered over.
 
 const TEST_PAGE = URL_ROOT +
   "doc_inspector_highlighter-comments.html";
 
 add_task(function* () {
   let {inspector, testActor} = yield openInspectorForURL(TEST_PAGE);
--- a/devtools/client/netmonitor/test/browser_net_simple-request-data.js
+++ b/devtools/client/netmonitor/test/browser_net_simple-request-data.js
@@ -2,24 +2,16 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 /**
  * Tests if requests render correct information in the menu UI.
  */
 
-// The following intermittent rejections should not be left uncaught. This test
-// has been whitelisted until the issue is fixed.
-//
-// NOTE: Whitelisting a class of rejections should be limited. Normally you
-//       should use "expectUncaughtRejection" to flag individual failures.
-Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
-PromiseTestUtils.whitelistRejectionsGlobally(/requestItem is undefined/);
-
 function test() {
   // Disable tcp fast open, because it is setting a response header indicator
   // (bug 1352274). TCP Fast Open is not present on all platforms therefore the
   // number of response headers will vary depending on the platform.
   Services.prefs.setBoolPref("network.tcp.tcp_fastopen_enable", false);
 
   let { L10N } = require("devtools/client/netmonitor/src/utils/l10n");
 
--- a/devtools/client/projecteditor/test/browser_projecteditor_editing_01.js
+++ b/devtools/client/projecteditor/test/browser_projecteditor_editing_01.js
@@ -1,14 +1,20 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("destroy");
+
 loadHelperScript("helper_edits.js");
 
 // Test ProjectEditor basic functionality
 add_task(function* () {
   let projecteditor = yield addProjectEditorTabForTempDirectory();
   let TEMP_PATH = projecteditor.project.allPaths()[0];
 
   is(getTempFile("").path, TEMP_PATH, "Temp path is set correctly.");
--- a/devtools/client/projecteditor/test/browser_projecteditor_editors_image.js
+++ b/devtools/client/projecteditor/test/browser_projecteditor_editors_image.js
@@ -1,14 +1,20 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("destroy");
+
 loadHelperScript("helper_edits.js");
 
 // Test ProjectEditor image editor functionality
 add_task(function* () {
   let projecteditor = yield addProjectEditorTabForTempDirectory();
   let TEMP_PATH = projecteditor.project.allPaths()[0];
 
   is(getTempFile("").path, TEMP_PATH, "Temp path is set correctly.");
--- a/devtools/client/projecteditor/test/browser_projecteditor_immediate_destroy.js
+++ b/devtools/client/projecteditor/test/browser_projecteditor_immediate_destroy.js
@@ -1,14 +1,21 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("destroy");
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.window is null");
+
 // Test that projecteditor can be destroyed in various states of loading
 // without causing any leaks or exceptions.
 
 add_task(function* () {
 
   info("Testing tab closure when projecteditor is in various states");
   let loaderUrl = "chrome://mochitests/content/browser/devtools/client/projecteditor/test/projecteditor-test.xul";
 
--- a/devtools/client/projecteditor/test/browser_projecteditor_saveall.js
+++ b/devtools/client/projecteditor/test/browser_projecteditor_saveall.js
@@ -1,14 +1,20 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("destroy");
+
 loadHelperScript("helper_edits.js");
 
 // Test ProjectEditor basic functionality
 add_task(function* () {
   let projecteditor = yield addProjectEditorTabForTempDirectory();
   let TEMP_PATH = projecteditor.project.allPaths()[0];
 
   is(getTempFile("").path, TEMP_PATH, "Temp path is set correctly.");
--- a/devtools/client/projecteditor/test/browser_projecteditor_tree_selection_02.js
+++ b/devtools/client/projecteditor/test/browser_projecteditor_tree_selection_02.js
@@ -1,14 +1,20 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("destroy");
+
 // Test that files get reselected in the tree when their editor
 // is focused.  https://bugzilla.mozilla.org/show_bug.cgi?id=1011116.
 
 add_task(function* () {
   let projecteditor = yield addProjectEditorTabForTempDirectory();
   let TEMP_PATH = projecteditor.project.allPaths()[0];
 
   is(getTempFile("").path, TEMP_PATH, "Temp path is set correctly.");
--- a/devtools/client/projecteditor/test/head.js
+++ b/devtools/client/projecteditor/test/head.js
@@ -1,30 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 var Cu = Components.utils;
-
-// There are shutdown issues for which multiple rejections are left uncaught.
-// This bug should be fixed, but for the moment devtools are whitelisted.
-//
-// NOTE: Entire directory whitelisting should be kept to a minimum. Normally you
-//       should use "expectUncaughtRejection" to flag individual failures.
-const {PromiseTestUtils} = Cu.import("resource://testing-common/PromiseTestUtils.jsm", {});
-PromiseTestUtils.whitelistRejectionsGlobally(/Component not initialized/);
-PromiseTestUtils.whitelistRejectionsGlobally(/Connection closed/);
-PromiseTestUtils.whitelistRejectionsGlobally(/destroy/);
-PromiseTestUtils.whitelistRejectionsGlobally(/is no longer, usable/);
-PromiseTestUtils.whitelistRejectionsGlobally(/this\._urls is null/);
-PromiseTestUtils.whitelistRejectionsGlobally(/this\.tabTarget is null/);
-PromiseTestUtils.whitelistRejectionsGlobally(/this\.toolbox is null/);
-PromiseTestUtils.whitelistRejectionsGlobally(/this\.webConsoleClient is null/);
-PromiseTestUtils.whitelistRejectionsGlobally(/this\.worker is null/);
-
 const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
 const {TargetFactory} = require("devtools/client/framework/target");
 const {console} = Cu.import("resource://gre/modules/Console.jsm", {});
 const promise = require("promise");
 const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {});
 const {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm", {});
 const ProjectEditor = require("devtools/client/projecteditor/lib/projecteditor");
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
--- a/devtools/client/responsivedesign/test/browser_responsive_cmd.js
+++ b/devtools/client/responsivedesign/test/browser_responsive_cmd.js
@@ -1,13 +1,19 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("destroy");
+
 function test() {
   let manager = ResponsiveUIManager;
   let done;
 
   function isOpen() {
     return gBrowser.getBrowserContainer(gBrowser.selectedBrowser)
                    .hasAttribute("responsivemode");
   }
--- a/devtools/client/shared/test/browser_telemetry_toolboxtabs_shadereditor.js
+++ b/devtools/client/shared/test/browser_telemetry_toolboxtabs_shadereditor.js
@@ -1,13 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed(
+  "Error: Shader Editor is still waiting for a WebGL context to be created.");
+
 const TEST_URI = "data:text/html;charset=utf-8," +
   "<p>browser_telemetry_toolboxtabs_shadereditor.js</p>";
 
 // Because we need to gather stats for the period of time that a tool has been
 // opened we make use of setTimeout() to create tool active times.
 const TOOL_DELAY = 200;
 const TOOL_PREF = "devtools.shadereditor.enabled";
 
--- a/devtools/client/shared/test/browser_toolbar_tooltip.js
+++ b/devtools/client/shared/test/browser_toolbar_tooltip.js
@@ -1,15 +1,23 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Tests that the developer toolbar works properly
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed(
+  "Protocol error (unknownError): Error: Got an invalid root window in DocumentWalker"
+);
+
 const TEST_URI = "data:text/html;charset=utf-8,<p>Tooltip Tests</p>";
 const PREF_DEVTOOLS_THEME = "devtools.theme";
 
 registerCleanupFunction(() => {
   // Set preferences back to their original values
   Services.prefs.clearUserPref(PREF_DEVTOOLS_THEME);
 });
 
--- a/devtools/client/webaudioeditor/test/browser_wa_first-run.js
+++ b/devtools/client/webaudioeditor/test/browser_wa_first-run.js
@@ -1,11 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Connection closed");
+
 /**
  * Tests that the reloading/onContentLoaded hooks work.
  */
 
 add_task(function* () {
   let { target, panel } = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
   let { gFront, $ } = panel.panelWin;
 
--- a/devtools/client/webaudioeditor/test/browser_wa_reset-01.js
+++ b/devtools/client/webaudioeditor/test/browser_wa_reset-01.js
@@ -1,11 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Connection closed");
+
 /**
  * Tests that reloading a tab will properly listen for the `start-context`
  * event and reshow the tools after reloading.
  */
 
 add_task(function* () {
   let { target, panel } = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
   let { gFront, $ } = panel.panelWin;
--- a/devtools/client/webaudioeditor/test/browser_wa_reset-04.js
+++ b/devtools/client/webaudioeditor/test/browser_wa_reset-04.js
@@ -1,11 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Connection closed");
+
 /**
  * Tests that switching to an iframe works fine.
  */
 
 add_task(function* () {
   Services.prefs.setBoolPref("devtools.command-button-frames.enabled", true);
 
   let { target, panel, toolbox } = yield initWebAudioEditor(IFRAME_CONTEXT_URL);
--- a/devtools/client/webaudioeditor/test/head.js
+++ b/devtools/client/webaudioeditor/test/head.js
@@ -1,30 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 "use strict";
 
 var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
-// There are shutdown issues for which multiple rejections are left uncaught.
-// This bug should be fixed, but for the moment devtools are whitelisted.
-//
-// NOTE: Entire directory whitelisting should be kept to a minimum. Normally you
-//       should use "expectUncaughtRejection" to flag individual failures.
-const { PromiseTestUtils } = Cu.import("resource://testing-common/PromiseTestUtils.jsm", {});
-PromiseTestUtils.whitelistRejectionsGlobally(/Component not initialized/);
-PromiseTestUtils.whitelistRejectionsGlobally(/Connection closed/);
-PromiseTestUtils.whitelistRejectionsGlobally(/destroy/);
-PromiseTestUtils.whitelistRejectionsGlobally(/is no longer, usable/);
-PromiseTestUtils.whitelistRejectionsGlobally(/this\._urls is null/);
-PromiseTestUtils.whitelistRejectionsGlobally(/this\.tabTarget is null/);
-PromiseTestUtils.whitelistRejectionsGlobally(/this\.toolbox is null/);
-PromiseTestUtils.whitelistRejectionsGlobally(/this\.webConsoleClient is null/);
-PromiseTestUtils.whitelistRejectionsGlobally(/this\.worker is null/);
-
 var { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
 var { Task } = require("devtools/shared/task");
 var Services = require("Services");
 var { gDevTools } = require("devtools/client/framework/devtools");
 var { TargetFactory } = require("devtools/client/framework/target");
 var { DebuggerServer } = require("devtools/server/main");
 var { generateUUID } = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
 
--- a/devtools/client/webconsole/test/browser_webconsole_output_01.js
+++ b/devtools/client/webconsole/test/browser_webconsole_output_01.js
@@ -4,16 +4,18 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 
 "use strict";
 
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("null");
+
 // Test the webconsole output for various types of objects.
 
 const TEST_URI = "data:text/html;charset=utf8,test for console output - 01";
 
 var {DebuggerServer} = require("devtools/server/main");
 
 var longString = (new Array(DebuggerServer.LONG_STRING_LENGTH + 4)).join("a");
 var initialString = longString.substring(0, DebuggerServer.LONG_STRING_INITIAL_LENGTH);
--- a/devtools/client/webconsole/test/browser_webconsole_output_04.js
+++ b/devtools/client/webconsole/test/browser_webconsole_output_04.js
@@ -4,16 +4,18 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 
 "use strict";
 
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("null");
+
 // Test the webconsole output for various types of objects.
 
 const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
                  "test/test-console-output-04.html";
 
 var inputTests = [
   // 0
   {
--- a/devtools/client/webconsole/test/browser_webconsole_output_dom_elements_01.js
+++ b/devtools/client/webconsole/test/browser_webconsole_output_dom_elements_01.js
@@ -3,16 +3,20 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejections should be fixed.
 
 "use strict";
 
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed(null);
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed(
+  "TypeError: this.toolbox is null");
+
 // Test the webconsole output for various types of DOM Nodes.
 
 const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
                  "test/test-console-output-dom-elements.html";
 
 var inputTests = [
   {
     input: "testBodyNode()",
--- a/devtools/client/webconsole/test/browser_webconsole_output_events.js
+++ b/devtools/client/webconsole/test/browser_webconsole_output_events.js
@@ -3,16 +3,18 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 
 "use strict";
 
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("null");
+
 // Test the webconsole output for DOM events.
 
 const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
                  "test/test-console-output-events.html";
 
 add_task(function* () {
   yield loadTab(TEST_URI);
 
--- a/devtools/server/actors/webextension-inspected-window.js
+++ b/devtools/server/actors/webextension-inspected-window.js
@@ -285,17 +285,17 @@ var WebExtensionInspectedWindowActor = p
             });
 
             this.customizedReload.start()
                 .then(() => {
                   delete this.customizedReload;
                 })
                 .catch(err => {
                   delete this.customizedReload;
-                  console.error(err);
+                  throw err;
                 });
           } catch (err) {
             // Cancel the customized reload (if any) on exception during the
             // reload setup.
             if (this.customizedReload) {
               this.customizedReload.stop(err);
             }
 
--- a/dom/base/test/browser_timeout_throttling_with_audio_playback.js
+++ b/dom/base/test/browser_timeout_throttling_with_audio_playback.js
@@ -1,15 +1,8 @@
-// The tab closing code leaves an uncaught rejection. This test has been
-// whitelisted until the issue is fixed.
-if (!gMultiProcessBrowser) {
-  Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
-  PromiseTestUtils.expectUncaughtRejection(/is no longer, usable/);
-}
-
 const kBaseURI = "http://mochi.test:8888/browser/dom/base/test/empty.html";
 const kPluginJS = "chrome://mochitests/content/browser/dom/base/test/plugin.js";
 var testURLs = [
   "http://mochi.test:8888/browser/dom/base/test/file_audioLoop.html",
   "http://mochi.test:8888/browser/dom/base/test/file_audioLoopInIframe.html",
   "http://mochi.test:8888/browser/dom/base/test/file_pluginAudio.html",
   "http://mochi.test:8888/browser/dom/base/test/file_webaudioLoop.html",
 ];
--- a/dom/tests/browser/helper_largeAllocation.js
+++ b/dom/tests/browser/helper_largeAllocation.js
@@ -288,17 +288,16 @@ function* largeAllocSuccessTests() {
     // process which was created for the normal content to be loaded into as the
     // browsing context was booted out of the fresh process. If we discover that
     // this was not a fresh process, we'll need to wait for another process.
     // Start listening now.
     epc = expectProcessCreated();
     if (!(yield getInLAProc(aBrowser))) {
       yield epc;
     } else {
-      epc.catch(() => {});
       epc.kill();
     }
 
     let pid3 = yield getPID(aBrowser);
 
     isnot(pid1, pid3, "PIDs 1 and 3 should not match");
     isnot(pid2, pid3, "PIDs 2 and 3 should not match");
     is(true, yield getInLAProc(aBrowser));
--- a/testing/mochitest/browser-test.js
+++ b/testing/mochitest/browser-test.js
@@ -149,27 +149,52 @@ function Tester(aTests, structuredLogger
 
   this.MemoryStats = simpleTestScope.MemoryStats;
   this.Task = Task;
   this.ContentTask = Components.utils.import("resource://testing-common/ContentTask.jsm", null).ContentTask;
   this.BrowserTestUtils = Components.utils.import("resource://testing-common/BrowserTestUtils.jsm", null).BrowserTestUtils;
   this.TestUtils = Components.utils.import("resource://testing-common/TestUtils.jsm", null).TestUtils;
   this.Task.Debugging.maintainStack = true;
   this.Promise = Components.utils.import("resource://gre/modules/Promise.jsm", null).Promise;
-  this.PromiseTestUtils = Components.utils.import("resource://testing-common/PromiseTestUtils.jsm", null).PromiseTestUtils;
   this.Assert = Components.utils.import("resource://testing-common/Assert.jsm", null).Assert;
 
-  this.PromiseTestUtils.init();
-
   this.SimpleTestOriginal = {};
   SIMPLETEST_OVERRIDES.forEach(m => {
     this.SimpleTestOriginal[m] = this.SimpleTest[m];
   });
 
   this._coverageCollector = null;
+
+  this._toleratedUncaughtRejections = null;
+  this._uncaughtErrorObserver = ({message, date, fileName, stack, lineNumber}) => {
+    let ex = message;
+    if (fileName || lineNumber) {
+      ex = {
+        fileName: fileName,
+        lineNumber: lineNumber,
+        message: message,
+        toString: function() {
+          return message;
+        }
+      };
+    }
+
+    // We may have a whitelist of rejections we wish to tolerate.
+    let pass = this._toleratedUncaughtRejections &&
+      this._toleratedUncaughtRejections.indexOf(message) != -1;
+    let name = "A promise chain failed to handle a rejection: ";
+    if (pass) {
+      name = "WARNING: (PLEASE FIX THIS AS PART OF BUG 1077403) " + name;
+    }
+
+    this.currentTest.addResult(new testResult({
+      pass, name, ex, todo: pass, stack,
+      allowFailure: this.currentTest.allowFailure,
+    }));
+  };
 }
 Tester.prototype = {
   EventUtils: {},
   SimpleTest: {},
   Task: null,
   ContentTask: null,
   ExtensionTestUtils: null,
   Assert: null,
@@ -214,16 +239,19 @@ Tester.prototype = {
     this._globalProperties = Object.keys(window);
     this._globalPropertyWhitelist = [
       "navigator", "constructor", "top",
       "Application",
       "__SS_tabsToRestore", "__SSi",
       "webConsoleCommandController",
     ];
 
+    this.Promise.Debugging.clearUncaughtErrorObservers();
+    this.Promise.Debugging.addUncaughtErrorObserver(this._uncaughtErrorObserver);
+
     if (this.tests.length)
       this.waitForGraphicsTestWindowToBeGone(this.nextTest.bind(this));
     else
       this.finish();
   },
 
   waitForGraphicsTestWindowToBeGone(aCallback) {
     let windowsEnum = Services.wm.getEnumerator(null);
@@ -311,33 +339,34 @@ Tester.prototype = {
                                     "finished window state check in " + time + "ms");
     }
 
     // Make sure the window is raised before each test.
     this.SimpleTest.waitForFocus(aCallback);
   },
 
   finish: function Tester_finish(aSkipSummary) {
+    this.Promise.Debugging.flushUncaughtErrors();
+
     var passCount = this.tests.reduce((a, f) => a + f.passCount, 0);
     var failCount = this.tests.reduce((a, f) => a + f.failCount, 0);
     var todoCount = this.tests.reduce((a, f) => a + f.todoCount, 0);
 
     // Include failures from window state checking prior to running the first test
     failCount += this.failuresFromInitialWindowState;
 
     if (this.repeat > 0) {
       --this.repeat;
       this.currentTestIndex = -1;
       this.nextTest();
     } else {
       TabDestroyObserver.destroy();
       Services.console.unregisterListener(this);
-
-      // It's important to terminate the module to avoid crashes on shutdown.
-      this.PromiseTestUtils.uninit();
+      this.Promise.Debugging.clearUncaughtErrorObservers();
+      this._treatUncaughtRejectionsAsFailures = false;
 
       // In the main process, we print the ShutdownLeaksCollector message here.
       let pid = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).processID;
       dump("Completed ShutdownLeaks collections in process " + pid + "\n");
 
       this.structuredLogger.info("TEST-START | Shutdown");
 
       if (this.tests.length) {
@@ -388,16 +417,17 @@ Tester.prototype = {
     } catch (ex) {
       // Swallow exception so we don't lead to another error being reported,
       // throwing us into an infinite loop
     }
   },
 
   nextTest: Task.async(function*() {
     if (this.currentTest) {
+      this.Promise.Debugging.flushUncaughtErrors();
       if (this._coverageCollector) {
         this._coverageCollector.recordTestCoverage(this.currentTest.path);
       }
 
       // Run cleanup functions for the current test before moving on to the
       // next one.
       let testScope = this.currentTest.scope;
       while (testScope.__cleanupFunctions.length > 0) {
@@ -419,16 +449,18 @@ Tester.prototype = {
           this.currentTest.todoCount === 0) {
         this.currentTest.addResult(new testResult({
           name: "This test contains no passes, no fails and no todos. Maybe" +
                 " it threw a silent exception? Make sure you use" +
                 " waitForExplicitFinish() if you need it.",
         }));
       }
 
+      this.Promise.Debugging.flushUncaughtErrors();
+
       let winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
                            .getInterface(Ci.nsIDOMWindowUtils);
       if (winUtils.isTestControllingRefreshes) {
         this.currentTest.addResult(new testResult({
           name: "test left refresh driver under test control",
         }));
         winUtils.restoreNormalRefresh();
       }
@@ -436,20 +468,16 @@ Tester.prototype = {
       if (this.SimpleTest.isExpectingUncaughtException()) {
         this.currentTest.addResult(new testResult({
           name: "expectUncaughtException was called but no uncaught" +
                 " exception was detected!",
           allowFailure: this.currentTest.allowFailure,
         }));
       }
 
-      this.PromiseTestUtils.ensureDOMPromiseRejectionsProcessed();
-      this.PromiseTestUtils.assertNoUncaughtRejections();
-      this.PromiseTestUtils.assertNoMoreExpectedRejections();
-
       Object.keys(window).forEach(function (prop) {
         if (parseInt(prop) == prop) {
           // This is a string which when parsed as an integer and then
           // stringified gives the original string.  As in, this is in fact a
           // string representation of an integer, so an index into
           // window.frames.  Skip those.
           return;
         }
@@ -715,17 +743,16 @@ Tester.prototype = {
       } : {
         name: message,
         pass: true,
         stack,
         allowFailure: currentTest.allowFailure,
       }));
     });
 
-    this.PromiseTestUtils.Assert = this.currentTest.scope.Assert;
     this.ContentTask.setTestScope(currentScope);
 
     // Allow Assert.jsm methods to be tacked to the current scope.
     this.currentTest.scope.export_assertions = function() {
       for (let func in this.Assert) {
         this[func] = this.Assert[func].bind(this.Assert);
       }
     };
@@ -757,41 +784,41 @@ Tester.prototype = {
        }));
       }
     }
 
     // Import the test script.
     try {
       this._scriptLoader.loadSubScript(this.currentTest.path,
                                        this.currentTest.scope);
+      this.Promise.Debugging.flushUncaughtErrors();
       // Run the test
       this.lastStartTime = Date.now();
       if (this.currentTest.scope.__tasks) {
         // This test consists of tasks, added via the `add_task()` API.
         if ("test" in this.currentTest.scope) {
           throw "Cannot run both a add_task test and a normal test at the same time.";
         }
         let Promise = this.Promise;
-        let PromiseTestUtils = this.PromiseTestUtils;
         this.Task.spawn(function*() {
           let task;
           while ((task = this.__tasks.shift())) {
             this.SimpleTest.info("Entering test " + task.name);
             try {
               yield task();
             } catch (ex) {
               currentTest.addResult(new testResult({
                 name: "Uncaught exception",
                 pass: this.SimpleTest.isExpectingUncaughtException(),
                 ex,
                 stack: (typeof ex == "object" && "stack" in ex) ? ex.stack : null,
                 allowFailure: currentTest.allowFailure,
               }));
             }
-            PromiseTestUtils.assertNoUncaughtRejections();
+            Promise.Debugging.flushUncaughtErrors();
             this.SimpleTest.info("Leaving test " + task.name);
           }
           this.finish();
         }.bind(currentScope));
       } else if (typeof this.currentTest.scope.test == "function") {
         this.currentTest.scope.test();
       } else {
         throw "This test didn't call add_task, nor did it define a generatorTest() function, nor did it define a test() function, so we don't know how to run it.";
@@ -1029,16 +1056,23 @@ function testScope(aTester, aTest, expec
   this.expectUncaughtException = function test_expectUncaughtException(aExpecting) {
     self.SimpleTest.expectUncaughtException(aExpecting);
   };
 
   this.ignoreAllUncaughtExceptions = function test_ignoreAllUncaughtExceptions(aIgnoring) {
     self.SimpleTest.ignoreAllUncaughtExceptions(aIgnoring);
   };
 
+  this.thisTestLeaksUncaughtRejectionsAndShouldBeFixed = function(...rejections) {
+    if (!aTester._toleratedUncaughtRejections) {
+      aTester._toleratedUncaughtRejections = [];
+    }
+    aTester._toleratedUncaughtRejections.push(...rejections);
+  };
+
   this.expectAssertions = function test_expectAssertions(aMin, aMax) {
     let min = aMin;
     let max = aMax;
     if (typeof(max) == "undefined") {
       max = min;
     }
     if (typeof(min) != "number" || typeof(max) != "number" ||
         min < 0 || max < min) {
--- a/testing/mochitest/tests/browser/browser.ini
+++ b/testing/mochitest/tests/browser/browser.ini
@@ -5,39 +5,35 @@ support-files =
 [browser_add_task.js]
 [browser_async.js]
 [browser_browserLoaded_content_loaded.js]
 [browser_BrowserTestUtils.js]
 support-files =
   dummy.html
 [browser_fail.js]
 [browser_fail_add_task.js]
-[browser_fail_add_task_uncaught_rejection.js]
 [browser_fail_async.js]
 [browser_fail_if.js]
 fail-if = true
 [browser_fail_throw.js]
 [browser_fail_timeout.js]
 skip-if = true # Disabled beacuse it takes too long (bug 1178959)
 [browser_fail_uncaught_rejection.js]
-[browser_fail_uncaught_rejection_expected.js]
-[browser_fail_uncaught_rejection_expected_multi.js]
 [browser_fail_unexpectedTimeout.js]
 skip-if = true # Disabled beacuse it takes too long (bug 1178959)
 [browser_getTestFile.js]
 support-files =
   test-dir/*
   waitForFocusPage.html
 [browser_head.js]
 [browser_pass.js]
 [browser_parameters.js]
 [browser_popupNode.js]
 [browser_popupNode_check.js]
 [browser_privileges.js]
 [browser_requestLongerTimeout.js]
 skip-if = true # Disabled beacuse it takes too long (bug 1178959)
 [browser_sanityException.js]
 [browser_sanityException2.js]
-[browser_uncaught_rejection_expected.js]
 [browser_waitForFocus.js]
 skip-if = (os == "win" && e10s && debug)
 [browser_zz_fail_openwindow.js]
 skip-if = true # this catches outside of the main loop to find an extra window
deleted file mode 100644
--- a/testing/mochitest/tests/browser/browser_fail_add_task_uncaught_rejection.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-setExpectedFailuresForSelfTest(8);
-
-// Keep "JSMPromise" separate so "Promise" still refers to native Promises.
-let JSMPromise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
-
-async function rejectOnNextTick(error) {
-  await Promise.resolve();
-
-  Promise.reject(error);
-  JSMPromise.reject(error);
-}
-
-add_task(function failWithoutError() {
-  yield rejectOnNextTick(undefined);
-});
-
-add_task(function failWithString() {
-  yield rejectOnNextTick("This is a string");
-});
-
-add_task(function failWithInt() {
-  yield rejectOnNextTick(42);
-});
-
-// This one should display a stack trace
-add_task(function failWithError() {
-  yield rejectOnNextTick(new Error("This is an error"));
-});
--- a/testing/mochitest/tests/browser/browser_fail_uncaught_rejection.js
+++ b/testing/mochitest/tests/browser/browser_fail_uncaught_rejection.js
@@ -1,19 +1,6 @@
-setExpectedFailuresForSelfTest(3);
-
-// Keep "JSMPromise" separate so "Promise" still refers to native Promises.
-let JSMPromise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
+setExpectedFailuresForSelfTest(1);
 
 function test() {
+  Components.utils.import("resource://gre/modules/Promise.jsm", this);
   Promise.reject(new Error("Promise rejection."));
-  JSMPromise.reject(new Error("Promise.jsm rejection."));
-  (async () => {
-    throw "Synchronous rejection from async function.";
-  })();
-
-  // The following rejections are caught, so they won't result in failures.
-  Promise.reject(new Error("Promise rejection.")).catch(() => {});
-  JSMPromise.reject(new Error("Promise.jsm rejection.")).catch(() => {});
-  (async () => {
-    throw "Synchronous rejection from async function.";
-  })().catch(() => {});
 }
deleted file mode 100644
--- a/testing/mochitest/tests/browser/browser_fail_uncaught_rejection_expected.js
+++ /dev/null
@@ -1,10 +0,0 @@
-setExpectedFailuresForSelfTest(1);
-
-// The test will fail because there is only one of two expected rejections.
-Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
-PromiseTestUtils.expectUncaughtRejection(/Promise rejection./);
-PromiseTestUtils.expectUncaughtRejection(/Promise rejection./);
-
-function test() {
-  Promise.reject(new Error("Promise rejection."));
-}
deleted file mode 100644
--- a/testing/mochitest/tests/browser/browser_fail_uncaught_rejection_expected_multi.js
+++ /dev/null
@@ -1,9 +0,0 @@
-setExpectedFailuresForSelfTest(1);
-
-// The test will fail because an expected uncaught rejection is actually caught.
-Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
-PromiseTestUtils.expectUncaughtRejection(/Promise rejection./);
-
-function test() {
-  Promise.reject(new Error("Promise rejection.")).catch(() => {});
-}
deleted file mode 100644
--- a/testing/mochitest/tests/browser/browser_uncaught_rejection_expected.js
+++ /dev/null
@@ -1,18 +0,0 @@
-// Keep "JSMPromise" separate so "Promise" still refers to native Promises.
-let JSMPromise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
-
-Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
-PromiseTestUtils.whitelistRejectionsGlobally(/Whitelisted rejection./);
-PromiseTestUtils.expectUncaughtRejection(/Promise.jsm rejection./);
-PromiseTestUtils.expectUncaughtRejection(/Promise.jsm rejection./);
-PromiseTestUtils.expectUncaughtRejection(/Promise rejection./);
-PromiseTestUtils.expectUncaughtRejection(/Promise rejection./);
-
-function test() {
-  Promise.reject(new Error("Promise rejection."));
-  Promise.reject(new Error("Promise rejection."));
-  Promise.reject(new Error("Whitelisted rejection."));
-  JSMPromise.reject(new Error("Promise.jsm rejection."));
-  JSMPromise.reject(new Error("Promise.jsm rejection."));
-  JSMPromise.reject(new Error("Whitelisted rejection."));
-}
--- a/toolkit/components/startup/tests/browser/browser_bug537449.js
+++ b/toolkit/components/startup/tests/browser/browser_bug537449.js
@@ -1,14 +1,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.docShell is null");
+
 SpecialPowers.pushPrefEnv({"set": [["dom.require_user_interaction_for_beforeunload", false]]});
 
 const TEST_URL = "http://example.com/browser/toolkit/components/startup/tests/browser/beforeunload.html";
 
 function test() {
   waitForExplicitFinish();
 
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, TEST_URL);
--- a/toolkit/content/tests/browser/browser_block_webAudio.js
+++ b/toolkit/content/tests/browser/browser_block_webAudio.js
@@ -1,17 +1,10 @@
 const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_webAudio.html";
 
-// The tab closing code leaves an uncaught rejection. This test has been
-// whitelisted until the issue is fixed.
-if (!gMultiProcessBrowser) {
-  Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
-  PromiseTestUtils.expectUncaughtRejection(/is no longer, usable/);
-}
-
 add_task(async function setup_test_preference() {
   await SpecialPowers.pushPrefEnv({"set": [
     ["media.useAudioChannelService.testing", true],
     ["media.block-autoplay-until-in-foreground", true]
   ]});
 });
 
 add_task(async function block_web_audio() {
--- a/toolkit/content/tests/browser/browser_mute_webAudio.js
+++ b/toolkit/content/tests/browser/browser_mute_webAudio.js
@@ -1,15 +1,8 @@
-// The tab closing code leaves an uncaught rejection. This test has been
-// whitelisted until the issue is fixed.
-if (!gMultiProcessBrowser) {
-  Cu.import("resource://testing-common/PromiseTestUtils.jsm", this);
-  PromiseTestUtils.expectUncaughtRejection(/is no longer, usable/);
-}
-
 const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_webAudio.html";
 
 async function click_icon(tab) {
   let icon = document.getAnonymousElementByAttribute(tab, "anonid", "soundplaying-icon");
 
   await hover_icon(icon, document.getElementById("tabbrowser-tab-tooltip"));
   EventUtils.synthesizeMouseAtCenter(icon, {button: 0});
   leave_icon(icon);
--- a/toolkit/modules/tests/modules/PromiseTestUtils.jsm
+++ b/toolkit/modules/tests/modules/PromiseTestUtils.jsm
@@ -48,23 +48,16 @@ this.PromiseTestUtils = {
    * When an uncaught rejection is detected, it is ignored if one of the
    * functions in this array returns true when called with the rejection details
    * as its only argument. When a function matches an expected rejection, it is
    * then removed from the array.
    */
   _rejectionIgnoreFns: [],
 
   /**
-   * If any of the functions in this array returns true when called with the
-   * rejection details as its only argument, the rejection is ignored. This
-   * happens after the "_rejectionIgnoreFns" array is processed.
-   */
-  _globalRejectionIgnoreFns: [],
-
-  /**
    * Called only by the test infrastructure, registers the rejection observers.
    *
    * This should be called only once, and a matching "uninit" call must be made
    * or the tests will crash on shutdown.
    */
   init() {
     if (this._initialized) {
       Cu.reportError("This object was already initialized.");
@@ -152,31 +145,23 @@ this.PromiseTestUtils = {
       let reason = PromiseDebugging.getState(promise).reason;
       if (reason === this._ensureDOMPromiseRejectionsProcessedReason) {
         // Ignore the special promise for ensureDOMPromiseRejectionsProcessed.
         return;
       }
       message = reason.message || ("" + reason);
     } catch (ex) {}
 
-    // We should convert the rejection stack to a string immediately. This is
-    // because the object might not be available when we report the rejection
-    // later, if the error occurred in a context that has been unloaded.
-    let stack = "(Unable to convert rejection stack to string.)";
-    try {
-      stack = "" + PromiseDebugging.getRejectionStack(promise);
-    } catch (ex) {}
-
     // It's important that we don't store any reference to the provided Promise
     // object or its value after this function returns in order to avoid leaks.
     this._rejections.push({
       id: PromiseDebugging.getPromiseID(promise),
       message,
       date: new Date(),
-      stack,
+      stack: PromiseDebugging.getRejectionStack(promise),
     });
   },
 
   // UncaughtRejectionObserver
   onConsumed(promise) {
     // We don't expect that many unhandled rejections will appear at the same
     // time, so the algorithm doesn't need to be optimized for that case.
     let id = PromiseDebugging.getPromiseID(promise);
@@ -205,29 +190,16 @@ this.PromiseTestUtils = {
    */
   expectUncaughtRejection(regExpOrCheckFn) {
     let checkFn = !("test" in regExpOrCheckFn) ? regExpOrCheckFn :
                   rejection => regExpOrCheckFn.test(rejection.message);
     this._rejectionIgnoreFns.push(checkFn);
   },
 
   /**
-   * Whitelists an entire class of Promise rejections. Usage of this function
-   * should be kept to a minimum because it has a broad scope and doesn't
-   * prevent new unhandled rejections of this class from being added.
-   *
-   * @param regExp
-   *        This should match the error message of the rejection.
-   */
-  whitelistRejectionsGlobally(regExp) {
-    this._globalRejectionIgnoreFns.push(
-      rejection => regExp.test(rejection.message));
-  },
-
-  /**
    * Fails the test if there are any uncaught rejections at this time that have
    * not been whitelisted using expectUncaughtRejection.
    *
    * Depending on the configuration of the test suite, this function might only
    * report the details of the first uncaught rejection that was generated.
    *
    * This is called by the test suite at the end of each test function.
    */
@@ -242,21 +214,16 @@ this.PromiseTestUtils = {
       // If one of the ignore functions matches, ignore the rejection, then
       // remove the function so that each function only matches one rejection.
       let index = this._rejectionIgnoreFns.findIndex(f => f(rejection));
       if (index != -1) {
         this._rejectionIgnoreFns.splice(index, 1);
         continue;
       }
 
-      // Check the global whitelisting functions.
-      if (this._globalRejectionIgnoreFns.some(fn => fn(rejection))) {
-        continue;
-      }
-
       // Report the error. This operation can throw an exception, depending on
       // the configuration of the test suite that handles the assertion.
       Assert.ok(false,
                 `A promise chain failed to handle a rejection:` +
                 ` ${rejection.message} - rejection date: ${rejection.date}` +
                 ` - stack: ${rejection.stack}`);
     }
   },
@@ -268,12 +235,10 @@ this.PromiseTestUtils = {
    * This is called by the test suite at the end of each test file.
    */
   assertNoMoreExpectedRejections() {
     // Only log this condition is there is a failure.
     if (this._rejectionIgnoreFns.length > 0) {
       Assert.equal(this._rejectionIgnoreFns.length, 0,
              "Unable to find a rejection expected by expectUncaughtRejection.");
     }
-    // Reset the list of expected rejections in case the test suite continues.
-    this._rejectionIgnoreFns = [];
   },
 };
--- a/toolkit/mozapps/extensions/test/browser/browser_bug570760.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_bug570760.js
@@ -1,12 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("");
+
 // Bug 570760 - Make ctrl-f and / focus the search box in the add-ons manager
 
 var gManagerWindow;
 var focusCount = 0;
 
 function test() {
   waitForExplicitFinish();
 
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_auth3.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_auth3.js
@@ -1,13 +1,20 @@
 // ----------------------------------------------------------------------------
 // Test whether an install fails when authentication is required and it is
 // canceled
 // This verifies bug 312473
 
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.docShell is null");
+
+
 function test() {
   Harness.authenticationCallback = get_auth_info;
   Harness.downloadFailedCallback = download_failed;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
   var pm = Services.perms;
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_auth4.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_auth4.js
@@ -1,8 +1,16 @@
+//
+// Whitelisting this test.
+// As part of bug 1077403, the leaking uncaught rejection should be fixed.
+//
+thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.docShell is null");
+
+
+// ----------------------------------------------------------------------------
 // Test whether a request for auth for an XPI switches to the appropriate tab
 var gNewTab;
 
 function test() {
   Harness.authenticationCallback = get_auth_info;
   Harness.downloadFailedCallback = download_failed;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
--- a/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/browser-test.js
+++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/browser-test.js
@@ -40,16 +40,17 @@ module.exports = {
     "ignoreAllUncaughtExceptions": false,
     "info": false,
     "is": false,
     "isnot": false,
     "ok": false,
     "privateNoteIntentionalCrash": false,
     "registerCleanupFunction": false,
     "requestLongerTimeout": false,
+    "thisTestLeaksUncaughtRejectionsAndShouldBeFixed": false,
     "todo": false,
     "todo_is": false,
     "todo_isnot": false,
     "waitForClipboard": false,
     "waitForExplicitFinish": false,
     "waitForFocus": false
   },