| // Copyright 2015 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| /** |
| * Creates wrappers for callbacks and calls testDone() when all callbacks |
| * have been invoked. Callbacks may return a promise to defer completion and |
| * continued processing of subsequent callbacks. |
| * @param {testing.Test} fixture |
| */ |
| function CallbackHelper(fixture) { |
| /** @type {Object} fixture */ |
| this.fixture_ = fixture; |
| /** @type {number} */ |
| this.pendingCallbacks_ = 0; |
| } |
| |
| CallbackHelper.prototype = { |
| /** |
| * @param {Function=} opt_callback |
| * @return {Function} |
| */ |
| wrap(opt_callback) { |
| const callback = opt_callback || function() {}; |
| const savedArgs = new SaveMockArguments(); |
| let lastCall = null; |
| const completionAction = callFunctionWithSavedArgs(savedArgs, function() { |
| if (lastCall) { |
| throw new Error('Called more than once, first call here: ' + lastCall); |
| } else { |
| lastCall = new Error().stack; |
| } |
| const result = callback.apply(this.fixture_, arguments); |
| if (result) { |
| if (!(result instanceof Promise)) { |
| throw new Error('Only support return type of Promise'); |
| } |
| result |
| .then( |
| () => { |
| if (--this.pendingCallbacks_ <= 0) { |
| CallbackHelper.testDone_(); |
| } |
| }, |
| reason => { |
| CallbackHelper.testDone_([false, reason.toString()]); |
| }) |
| .catch(reason => { |
| CallbackHelper.testDone_([false, reason.toString()]); |
| }); |
| } else { |
| if (--this.pendingCallbacks_ <= 0) { |
| CallbackHelper.testDone_(); |
| } |
| } |
| }.bind(this)); |
| // runAllActionsAsync catches exceptions and puts them in the test |
| // framework's list of errors and fails the test if appropriate. |
| const runAll = runAllActionsAsync(WhenTestDone.ASSERT, completionAction); |
| ++this.pendingCallbacks_; |
| return function() { |
| savedArgs.arguments = Array.prototype.slice.call(arguments); |
| runAll.invoke(); |
| }; |
| }, |
| }; |
| |
| /** |
| * @private |
| */ |
| CallbackHelper.testDone_ = this.testDone; |
| // Remove testDone for public use since directly using it conflicts with |
| // this callback helper. |
| delete this.testDone; |