summaryrefslogtreecommitdiffstats
path: root/toolkit/modules/tests/PromiseTestUtils.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/modules/tests/PromiseTestUtils.jsm')
-rw-r--r--toolkit/modules/tests/PromiseTestUtils.jsm241
1 files changed, 0 insertions, 241 deletions
diff --git a/toolkit/modules/tests/PromiseTestUtils.jsm b/toolkit/modules/tests/PromiseTestUtils.jsm
deleted file mode 100644
index d60b785a5..000000000
--- a/toolkit/modules/tests/PromiseTestUtils.jsm
+++ /dev/null
@@ -1,241 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/*
- * Detects and reports unhandled rejections during test runs. Test harnesses
- * will fail tests in this case, unless the test whitelists itself.
- */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = [
- "PromiseTestUtils",
-];
-
-const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
-
-Cu.import("resource://gre/modules/Services.jsm", this);
-
-// Keep "JSMPromise" separate so "Promise" still refers to DOM Promises.
-let JSMPromise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
-
-// For now, we need test harnesses to provide a reference to Assert.jsm.
-let Assert = null;
-
-this.PromiseTestUtils = {
- /**
- * Array of objects containing the details of the Promise rejections that are
- * currently left uncaught. This includes DOM Promise and Promise.jsm. When
- * rejections in DOM Promises are consumed, they are removed from this list.
- *
- * The objects contain at least the following properties:
- * {
- * message: The error message associated with the rejection, if any.
- * date: Date object indicating when the rejection was observed.
- * id: For DOM Promise only, the Promise ID from PromiseDebugging. This is
- * only used for tracking and should not be checked by the callers.
- * stack: nsIStackFrame, SavedFrame, or string indicating the stack at the
- * time the rejection was triggered. May also be null if the
- * rejection was triggered while a script was on the stack.
- * }
- */
- _rejections: [],
-
- /**
- * 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: [],
-
- /**
- * 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.");
- return;
- }
-
- PromiseDebugging.addUncaughtRejectionObserver(this);
-
- // Promise.jsm rejections are only reported to this observer when requested,
- // so we don't have to store a key to remove them when consumed.
- JSMPromise.Debugging.addUncaughtErrorObserver(
- rejection => this._rejections.push(rejection));
-
- this._initialized = true;
- },
- _initialized: false,
-
- /**
- * Called only by the test infrastructure, unregisters the observers.
- */
- uninit() {
- if (!this._initialized) {
- return;
- }
-
- PromiseDebugging.removeUncaughtRejectionObserver(this);
- JSMPromise.Debugging.clearUncaughtErrorObservers();
-
- this._initialized = false;
- },
-
- /**
- * Called only by the test infrastructure, spins the event loop until the
- * messages for pending DOM Promise rejections have been processed.
- */
- ensureDOMPromiseRejectionsProcessed() {
- let observed = false;
- let observer = {
- onLeftUncaught: promise => {
- if (PromiseDebugging.getState(promise).reason ===
- this._ensureDOMPromiseRejectionsProcessedReason) {
- observed = true;
- }
- },
- onConsumed() {},
- };
-
- PromiseDebugging.addUncaughtRejectionObserver(observer);
- Promise.reject(this._ensureDOMPromiseRejectionsProcessedReason);
- while (!observed) {
- Services.tm.mainThread.processNextEvent(true);
- }
- PromiseDebugging.removeUncaughtRejectionObserver(observer);
- },
- _ensureDOMPromiseRejectionsProcessedReason: {},
-
- /**
- * Called only by the tests for PromiseDebugging.addUncaughtRejectionObserver
- * and for JSMPromise.Debugging, disables the observers in this module.
- */
- disableUncaughtRejectionObserverForSelfTest() {
- this.uninit();
- },
-
- /**
- * Called by tests that have been whitelisted, disables the observers in this
- * module. For new tests where uncaught rejections are expected, you should
- * use the more granular expectUncaughtRejection function instead.
- */
- thisTestLeaksUncaughtRejectionsAndShouldBeFixed() {
- this.uninit();
- },
-
- /**
- * Sets or updates the Assert object instance to be used for error reporting.
- */
- set Assert(assert) {
- Assert = assert;
- },
-
- // UncaughtRejectionObserver
- onLeftUncaught(promise) {
- let message = "(Unable to convert rejection reason to string.)";
- try {
- let reason = PromiseDebugging.getState(promise).reason;
- if (reason === this._ensureDOMPromiseRejectionsProcessedReason) {
- // Ignore the special promise for ensureDOMPromiseRejectionsProcessed.
- return;
- }
- message = reason.message || ("" + reason);
- } 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: 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);
- let index = this._rejections.findIndex(rejection => rejection.id == id);
- // If we get a consumption notification for a rejection that was left
- // uncaught before this module was initialized, we can safely ignore it.
- if (index != -1) {
- this._rejections.splice(index, 1);
- }
- },
-
- /**
- * Informs the test suite that the test code will generate a Promise rejection
- * that will still be unhandled when the test file terminates.
- *
- * This method must be called once for each instance of Promise that is
- * expected to be uncaught, even if the rejection reason is the same for each
- * instance.
- *
- * If the expected rejection does not occur, the test will fail.
- *
- * @param regExpOrCheckFn
- * This can either be a regular expression that should match the error
- * message of the rejection, or a check function that is invoked with
- * the rejection details object as its first argument.
- */
- expectUncaughtRejection(regExpOrCheckFn) {
- let checkFn = !("test" in regExpOrCheckFn) ? regExpOrCheckFn :
- rejection => regExpOrCheckFn.test(rejection.message);
- this._rejectionIgnoreFns.push(checkFn);
- },
-
- /**
- * 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.
- */
- assertNoUncaughtRejections() {
- // Ask Promise.jsm to report all uncaught rejections to the observer now.
- JSMPromise.Debugging.flushUncaughtErrors();
-
- // If there is any uncaught rejection left at this point, the test fails.
- while (this._rejections.length > 0) {
- let rejection = this._rejections.shift();
-
- // 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;
- }
-
- // 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}`);
- }
- },
-
- /**
- * Fails the test if any rejection indicated by expectUncaughtRejection has
- * not yet been reported at this time.
- *
- * 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.");
- }
- },
-};