diff options
Diffstat (limited to 'toolkit/modules/tests/PromiseTestUtils.jsm')
-rw-r--r-- | toolkit/modules/tests/PromiseTestUtils.jsm | 241 |
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."); - } - }, -}; |