690 lines
20 KiB
JavaScript
690 lines
20 KiB
JavaScript
// Copyright 2009 The Closure Library Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS-IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
/**
|
|
* @fileoverview Defines test classes for tests that can wait for conditions.
|
|
*
|
|
* Normal unit tests must complete their test logic within a single function
|
|
* execution. This is ideal for most tests, but makes it difficult to test
|
|
* routines that require real time to complete. The tests and TestCase in this
|
|
* file allow for tests that can wait until a condition is true before
|
|
* continuing execution.
|
|
*
|
|
* Each test has the typical three phases of execution: setUp, the test itself,
|
|
* and tearDown. During each phase, the test function may add wait conditions,
|
|
* which result in new test steps being added for that phase. All steps in a
|
|
* given phase must complete before moving on to the next phase. An error in
|
|
* any phase will stop that test and report the error to the test runner.
|
|
*
|
|
* This class should not be used where adequate mocks exist. Time-based routines
|
|
* should use the MockClock, which runs much faster and provides equivalent
|
|
* results. Continuation tests should be used for testing code that depends on
|
|
* browser behaviors that are difficult to mock. For example, testing code that
|
|
* relies on Iframe load events, event or layout code that requires a setTimeout
|
|
* to become valid, and other browser-dependent native object interactions for
|
|
* which mocks are insufficient.
|
|
*
|
|
* Sample usage:
|
|
*
|
|
* <pre>
|
|
* var testCase = new goog.testing.ContinuationTestCase();
|
|
* testCase.autoDiscoverTests();
|
|
*
|
|
* if (typeof G_testRunner != 'undefined') {
|
|
* G_testRunner.initialize(testCase);
|
|
* }
|
|
*
|
|
* function testWaiting() {
|
|
* var someVar = true;
|
|
* waitForTimeout(function() {
|
|
* assertTrue(someVar)
|
|
* }, 500);
|
|
* }
|
|
*
|
|
* function testWaitForEvent() {
|
|
* var et = goog.events.EventTarget();
|
|
* waitForEvent(et, 'test', function() {
|
|
* // Test step runs after the event fires.
|
|
* })
|
|
* et.dispatchEvent(et, 'test');
|
|
* }
|
|
*
|
|
* function testWaitForCondition() {
|
|
* var counter = 0;
|
|
*
|
|
* waitForCondition(function() {
|
|
* // This function is evaluated periodically until it returns true, or it
|
|
* // times out.
|
|
* return ++counter >= 3;
|
|
* }, function() {
|
|
* // This test step is run once the condition becomes true.
|
|
* assertEquals(3, counter);
|
|
* });
|
|
* }
|
|
* </pre>
|
|
*
|
|
* @author brenneman@google.com (Shawn Brenneman)
|
|
*/
|
|
|
|
|
|
goog.provide('goog.testing.ContinuationTestCase');
|
|
goog.provide('goog.testing.ContinuationTestCase.Step');
|
|
goog.provide('goog.testing.ContinuationTestCase.Test');
|
|
|
|
goog.require('goog.array');
|
|
goog.require('goog.events.EventHandler');
|
|
goog.require('goog.testing.TestCase');
|
|
goog.require('goog.testing.TestCase.Test');
|
|
goog.require('goog.testing.asserts');
|
|
|
|
|
|
|
|
/**
|
|
* Constructs a test case that supports tests with continuations. Test functions
|
|
* may issue "wait" commands that suspend the test temporarily and continue once
|
|
* the wait condition is met.
|
|
*
|
|
* @param {string=} opt_name Optional name for the test case.
|
|
* @constructor
|
|
* @extends {goog.testing.TestCase}
|
|
*/
|
|
goog.testing.ContinuationTestCase = function(opt_name) {
|
|
goog.testing.TestCase.call(this, opt_name);
|
|
|
|
/**
|
|
* An event handler for waiting on Closure or browser events during tests.
|
|
* @type {goog.events.EventHandler}
|
|
* @private
|
|
*/
|
|
this.handler_ = new goog.events.EventHandler(this);
|
|
};
|
|
goog.inherits(goog.testing.ContinuationTestCase, goog.testing.TestCase);
|
|
|
|
|
|
/**
|
|
* The default maximum time to wait for a single test step in milliseconds.
|
|
* @type {number}
|
|
*/
|
|
goog.testing.ContinuationTestCase.MAX_TIMEOUT = 1000;
|
|
|
|
|
|
/**
|
|
* Lock used to prevent multiple test steps from running recursively.
|
|
* @type {boolean}
|
|
* @private
|
|
*/
|
|
goog.testing.ContinuationTestCase.locked_ = false;
|
|
|
|
|
|
/**
|
|
* The current test being run.
|
|
* @type {goog.testing.ContinuationTestCase.Test}
|
|
* @private
|
|
*/
|
|
goog.testing.ContinuationTestCase.prototype.currentTest_ = null;
|
|
|
|
|
|
/**
|
|
* Enables or disables the wait functions in the global scope.
|
|
* @param {boolean} enable Whether the wait functions should be exported.
|
|
* @private
|
|
*/
|
|
goog.testing.ContinuationTestCase.prototype.enableWaitFunctions_ =
|
|
function(enable) {
|
|
if (enable) {
|
|
goog.exportSymbol('waitForCondition',
|
|
goog.bind(this.waitForCondition, this));
|
|
goog.exportSymbol('waitForEvent', goog.bind(this.waitForEvent, this));
|
|
goog.exportSymbol('waitForTimeout', goog.bind(this.waitForTimeout, this));
|
|
} else {
|
|
// Internet Explorer doesn't allow deletion of properties on the window.
|
|
goog.global['waitForCondition'] = undefined;
|
|
goog.global['waitForEvent'] = undefined;
|
|
goog.global['waitForTimeout'] = undefined;
|
|
}
|
|
};
|
|
|
|
|
|
/** @override */
|
|
goog.testing.ContinuationTestCase.prototype.runTests = function() {
|
|
this.enableWaitFunctions_(true);
|
|
goog.testing.ContinuationTestCase.superClass_.runTests.call(this);
|
|
};
|
|
|
|
|
|
/** @override */
|
|
goog.testing.ContinuationTestCase.prototype.finalize = function() {
|
|
this.enableWaitFunctions_(false);
|
|
goog.testing.ContinuationTestCase.superClass_.finalize.call(this);
|
|
};
|
|
|
|
|
|
/** @override */
|
|
goog.testing.ContinuationTestCase.prototype.cycleTests = function() {
|
|
// Get the next test in the queue.
|
|
if (!this.currentTest_) {
|
|
this.currentTest_ = this.createNextTest_();
|
|
}
|
|
|
|
// Run the next step of the current test, or exit if all tests are complete.
|
|
if (this.currentTest_) {
|
|
this.runNextStep_();
|
|
} else {
|
|
this.finalize();
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Creates the next test in the queue.
|
|
* @return {goog.testing.ContinuationTestCase.Test} The next test to execute, or
|
|
* null if no pending tests remain.
|
|
* @private
|
|
*/
|
|
goog.testing.ContinuationTestCase.prototype.createNextTest_ = function() {
|
|
var test = this.next();
|
|
if (!test) {
|
|
return null;
|
|
}
|
|
|
|
|
|
var name = test.name;
|
|
goog.testing.TestCase.currentTestName = name;
|
|
this.result_.runCount++;
|
|
this.log('Running test: ' + name);
|
|
|
|
return new goog.testing.ContinuationTestCase.Test(
|
|
new goog.testing.TestCase.Test(name, this.setUp, this),
|
|
test,
|
|
new goog.testing.TestCase.Test(name, this.tearDown, this));
|
|
};
|
|
|
|
|
|
/**
|
|
* Cleans up a finished test and cycles to the next test.
|
|
* @private
|
|
*/
|
|
goog.testing.ContinuationTestCase.prototype.finishTest_ = function() {
|
|
var err = this.currentTest_.getError();
|
|
if (err) {
|
|
this.doError(this.currentTest_, err);
|
|
} else {
|
|
this.doSuccess(this.currentTest_);
|
|
}
|
|
|
|
goog.testing.TestCase.currentTestName = null;
|
|
this.currentTest_ = null;
|
|
this.locked_ = false;
|
|
this.handler_.removeAll();
|
|
|
|
this.timeout(goog.bind(this.cycleTests, this), 0);
|
|
};
|
|
|
|
|
|
/**
|
|
* Executes the next step in the current phase, advancing through each phase as
|
|
* all steps are completed.
|
|
* @private
|
|
*/
|
|
goog.testing.ContinuationTestCase.prototype.runNextStep_ = function() {
|
|
if (this.locked_) {
|
|
// Attempting to run a step before the previous step has finished. Try again
|
|
// after that step has released the lock.
|
|
return;
|
|
}
|
|
|
|
var phase = this.currentTest_.getCurrentPhase();
|
|
|
|
if (!phase || !phase.length) {
|
|
// No more steps for this test.
|
|
this.finishTest_();
|
|
return;
|
|
}
|
|
|
|
// Find the next step that is not in a wait state.
|
|
var stepIndex = goog.array.findIndex(phase, function(step) {
|
|
return !step.waiting;
|
|
});
|
|
|
|
if (stepIndex < 0) {
|
|
// All active steps are currently waiting. Return until one wakes up.
|
|
return;
|
|
}
|
|
|
|
this.locked_ = true;
|
|
var step = phase[stepIndex];
|
|
|
|
try {
|
|
step.execute();
|
|
// Remove the successfully completed step. If an error is thrown, all steps
|
|
// will be removed for this phase.
|
|
goog.array.removeAt(phase, stepIndex);
|
|
|
|
} catch (e) {
|
|
this.currentTest_.setError(e);
|
|
|
|
// An assertion has failed, or an exception was raised. Clear the current
|
|
// phase, whether it is setUp, test, or tearDown.
|
|
this.currentTest_.cancelCurrentPhase();
|
|
|
|
// Cancel the setUp and test phase no matter where the error occurred. The
|
|
// tearDown phase will still run if it has pending steps.
|
|
this.currentTest_.cancelTestPhase();
|
|
}
|
|
|
|
this.locked_ = false;
|
|
this.runNextStep_();
|
|
};
|
|
|
|
|
|
/**
|
|
* Creates a new test step that will run after a user-specified
|
|
* timeout. No guarantee is made on the execution order of the
|
|
* continuation, except for those provided by each browser's
|
|
* window.setTimeout. In particular, if two continuations are
|
|
* registered at the same time with very small delta for their
|
|
* durations, this class can not guarantee that the continuation with
|
|
* the smaller duration will be executed first.
|
|
* @param {Function} continuation The test function to invoke after the timeout.
|
|
* @param {number=} opt_duration The length of the timeout in milliseconds.
|
|
*/
|
|
goog.testing.ContinuationTestCase.prototype.waitForTimeout =
|
|
function(continuation, opt_duration) {
|
|
var step = this.addStep_(continuation);
|
|
step.setTimeout(goog.bind(this.handleComplete_, this, step),
|
|
opt_duration || 0);
|
|
};
|
|
|
|
|
|
/**
|
|
* Creates a new test step that will run after an event has fired. If the event
|
|
* does not fire within a reasonable timeout, the test will fail.
|
|
* @param {goog.events.EventTarget|EventTarget} eventTarget The target that will
|
|
* fire the event.
|
|
* @param {string} eventType The type of event to listen for.
|
|
* @param {Function} continuation The test function to invoke after the event
|
|
* fires.
|
|
*/
|
|
goog.testing.ContinuationTestCase.prototype.waitForEvent = function(
|
|
eventTarget,
|
|
eventType,
|
|
continuation) {
|
|
|
|
var step = this.addStep_(continuation);
|
|
|
|
var duration = goog.testing.ContinuationTestCase.MAX_TIMEOUT;
|
|
step.setTimeout(goog.bind(this.handleTimeout_, this, step, duration),
|
|
duration);
|
|
|
|
this.handler_.listenOnce(eventTarget,
|
|
eventType,
|
|
goog.bind(this.handleComplete_, this, step));
|
|
};
|
|
|
|
|
|
/**
|
|
* Creates a new test step which will run once a condition becomes true. The
|
|
* condition will be polled at a user-specified interval until it becomes true,
|
|
* or until a maximum timeout is reached.
|
|
* @param {Function} condition The condition to poll.
|
|
* @param {Function} continuation The test code to evaluate once the condition
|
|
* becomes true.
|
|
* @param {number=} opt_interval The polling interval in milliseconds.
|
|
* @param {number=} opt_maxTimeout The maximum amount of time to wait for the
|
|
* condition in milliseconds (defaults to 1000).
|
|
*/
|
|
goog.testing.ContinuationTestCase.prototype.waitForCondition = function(
|
|
condition,
|
|
continuation,
|
|
opt_interval,
|
|
opt_maxTimeout) {
|
|
|
|
var interval = opt_interval || 100;
|
|
var timeout = opt_maxTimeout || goog.testing.ContinuationTestCase.MAX_TIMEOUT;
|
|
|
|
var step = this.addStep_(continuation);
|
|
this.testCondition_(step, condition, goog.now(), interval, timeout);
|
|
};
|
|
|
|
|
|
/**
|
|
* Creates a new asynchronous test step which will be added to the current test
|
|
* phase.
|
|
* @param {Function} func The test function that will be executed for this step.
|
|
* @return {goog.testing.ContinuationTestCase.Step} A new test step.
|
|
* @private
|
|
*/
|
|
goog.testing.ContinuationTestCase.prototype.addStep_ = function(func) {
|
|
if (!this.currentTest_) {
|
|
throw Error('Cannot add test steps outside of a running test.');
|
|
}
|
|
|
|
var step = new goog.testing.ContinuationTestCase.Step(
|
|
this.currentTest_.name,
|
|
func,
|
|
this.currentTest_.scope);
|
|
this.currentTest_.addStep(step);
|
|
return step;
|
|
};
|
|
|
|
|
|
/**
|
|
* Handles completion of a step's wait condition. Advances the test, allowing
|
|
* the step's test method to run.
|
|
* @param {goog.testing.ContinuationTestCase.Step} step The step that has
|
|
* finished waiting.
|
|
* @private
|
|
*/
|
|
goog.testing.ContinuationTestCase.prototype.handleComplete_ = function(step) {
|
|
step.clearTimeout();
|
|
step.waiting = false;
|
|
this.runNextStep_();
|
|
};
|
|
|
|
|
|
/**
|
|
* Handles the timeout event for a step that has exceeded the maximum time. This
|
|
* causes the current test to fail.
|
|
* @param {goog.testing.ContinuationTestCase.Step} step The timed-out step.
|
|
* @param {number} duration The length of the timeout in milliseconds.
|
|
* @private
|
|
*/
|
|
goog.testing.ContinuationTestCase.prototype.handleTimeout_ =
|
|
function(step, duration) {
|
|
step.ref = function() {
|
|
fail('Continuation timed out after ' + duration + 'ms.');
|
|
};
|
|
|
|
// Since the test is failing, cancel any other pending event listeners.
|
|
this.handler_.removeAll();
|
|
this.handleComplete_(step);
|
|
};
|
|
|
|
|
|
/**
|
|
* Tests a wait condition and executes the associated test step once the
|
|
* condition is true.
|
|
*
|
|
* If the condition does not become true before the maximum duration, the
|
|
* interval will stop and the test step will fail in the kill timer.
|
|
*
|
|
* @param {goog.testing.ContinuationTestCase.Step} step The waiting test step.
|
|
* @param {Function} condition The test condition.
|
|
* @param {number} startTime Time when the test step began waiting.
|
|
* @param {number} interval The duration in milliseconds to wait between tests.
|
|
* @param {number} timeout The maximum amount of time to wait for the condition
|
|
* to become true. Measured from the startTime in milliseconds.
|
|
* @private
|
|
*/
|
|
goog.testing.ContinuationTestCase.prototype.testCondition_ = function(
|
|
step,
|
|
condition,
|
|
startTime,
|
|
interval,
|
|
timeout) {
|
|
|
|
var duration = goog.now() - startTime;
|
|
|
|
if (condition()) {
|
|
this.handleComplete_(step);
|
|
} else if (duration < timeout) {
|
|
step.setTimeout(goog.bind(this.testCondition_,
|
|
this,
|
|
step,
|
|
condition,
|
|
startTime,
|
|
interval,
|
|
timeout),
|
|
interval);
|
|
} else {
|
|
this.handleTimeout_(step, duration);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* Creates a continuation test case, which consists of multiple test steps that
|
|
* occur in several phases.
|
|
*
|
|
* The steps are distributed between setUp, test, and tearDown phases. During
|
|
* the execution of each step, 0 or more steps may be added to the current
|
|
* phase. Once all steps in a phase have completed, the next phase will be
|
|
* executed.
|
|
*
|
|
* If any errors occur (such as an assertion failure), the setUp and Test phases
|
|
* will be cancelled immediately. The tearDown phase will always start, but may
|
|
* be cancelled as well if it raises an error.
|
|
*
|
|
* @param {goog.testing.TestCase.Test} setUp A setUp test method to run before
|
|
* the main test phase.
|
|
* @param {goog.testing.TestCase.Test} test A test method to run.
|
|
* @param {goog.testing.TestCase.Test} tearDown A tearDown test method to run
|
|
* after the test method completes or fails.
|
|
* @constructor
|
|
* @extends {goog.testing.TestCase.Test}
|
|
*/
|
|
goog.testing.ContinuationTestCase.Test = function(setUp, test, tearDown) {
|
|
// This test container has a name, but no evaluation function or scope.
|
|
goog.testing.TestCase.Test.call(this, test.name, null, null);
|
|
|
|
/**
|
|
* The list of test steps to run during setUp.
|
|
* @type {Array.<goog.testing.TestCase.Test>}
|
|
* @private
|
|
*/
|
|
this.setUp_ = [setUp];
|
|
|
|
/**
|
|
* The list of test steps to run for the actual test.
|
|
* @type {Array.<goog.testing.TestCase.Test>}
|
|
* @private
|
|
*/
|
|
this.test_ = [test];
|
|
|
|
/**
|
|
* The list of test steps to run during the tearDown phase.
|
|
* @type {Array.<goog.testing.TestCase.Test>}
|
|
* @private
|
|
*/
|
|
this.tearDown_ = [tearDown];
|
|
};
|
|
goog.inherits(goog.testing.ContinuationTestCase.Test,
|
|
goog.testing.TestCase.Test);
|
|
|
|
|
|
/**
|
|
* The first error encountered during the test run, if any.
|
|
* @type {Error}
|
|
* @private
|
|
*/
|
|
goog.testing.ContinuationTestCase.Test.prototype.error_ = null;
|
|
|
|
|
|
/**
|
|
* @return {Error} The first error to be raised during the test run or null if
|
|
* no errors occurred.
|
|
*/
|
|
goog.testing.ContinuationTestCase.Test.prototype.getError = function() {
|
|
return this.error_;
|
|
};
|
|
|
|
|
|
/**
|
|
* Sets an error for the test so it can be reported. Only the first error set
|
|
* during a test will be reported. Additional errors that occur in later test
|
|
* phases will be discarded.
|
|
* @param {Error} e An error.
|
|
*/
|
|
goog.testing.ContinuationTestCase.Test.prototype.setError = function(e) {
|
|
this.error_ = this.error_ || e;
|
|
};
|
|
|
|
|
|
/**
|
|
* @return {Array.<goog.testing.TestCase.Test>} The current phase of steps
|
|
* being processed. Returns null if all steps have been completed.
|
|
*/
|
|
goog.testing.ContinuationTestCase.Test.prototype.getCurrentPhase = function() {
|
|
if (this.setUp_.length) {
|
|
return this.setUp_;
|
|
}
|
|
|
|
if (this.test_.length) {
|
|
return this.test_;
|
|
}
|
|
|
|
if (this.tearDown_.length) {
|
|
return this.tearDown_;
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
|
|
/**
|
|
* Adds a new test step to the end of the current phase. The new step will wait
|
|
* for a condition to be met before running, or will fail after a timeout.
|
|
* @param {goog.testing.ContinuationTestCase.Step} step The test step to add.
|
|
*/
|
|
goog.testing.ContinuationTestCase.Test.prototype.addStep = function(step) {
|
|
var phase = this.getCurrentPhase();
|
|
if (phase) {
|
|
phase.push(step);
|
|
} else {
|
|
throw Error('Attempted to add a step to a completed test.');
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Cancels all remaining steps in the current phase. Called after an error in
|
|
* any phase occurs.
|
|
*/
|
|
goog.testing.ContinuationTestCase.Test.prototype.cancelCurrentPhase =
|
|
function() {
|
|
this.cancelPhase_(this.getCurrentPhase());
|
|
};
|
|
|
|
|
|
/**
|
|
* Skips the rest of the setUp and test phases, but leaves the tearDown phase to
|
|
* clean up.
|
|
*/
|
|
goog.testing.ContinuationTestCase.Test.prototype.cancelTestPhase = function() {
|
|
this.cancelPhase_(this.setUp_);
|
|
this.cancelPhase_(this.test_);
|
|
};
|
|
|
|
|
|
/**
|
|
* Clears a test phase and cancels any pending steps found.
|
|
* @param {Array.<goog.testing.TestCase.Test>} phase A list of test steps.
|
|
* @private
|
|
*/
|
|
goog.testing.ContinuationTestCase.Test.prototype.cancelPhase_ =
|
|
function(phase) {
|
|
while (phase && phase.length) {
|
|
var step = phase.pop();
|
|
if (step instanceof goog.testing.ContinuationTestCase.Step) {
|
|
step.clearTimeout();
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* Constructs a single step in a larger continuation test. Each step is similar
|
|
* to a typical TestCase test, except it may wait for an event or timeout to
|
|
* occur before running the test function.
|
|
*
|
|
* @param {string} name The test name.
|
|
* @param {Function} ref The test function to run.
|
|
* @param {Object=} opt_scope The object context to run the test in.
|
|
* @constructor
|
|
* @extends {goog.testing.TestCase.Test}
|
|
*/
|
|
goog.testing.ContinuationTestCase.Step = function(name, ref, opt_scope) {
|
|
goog.testing.TestCase.Test.call(this, name, ref, opt_scope);
|
|
};
|
|
goog.inherits(goog.testing.ContinuationTestCase.Step,
|
|
goog.testing.TestCase.Test);
|
|
|
|
|
|
/**
|
|
* Whether the step is currently waiting for a condition to continue. All new
|
|
* steps begin in wait state.
|
|
* @type {boolean}
|
|
*/
|
|
goog.testing.ContinuationTestCase.Step.prototype.waiting = true;
|
|
|
|
|
|
/**
|
|
* A saved reference to window.clearTimeout so that MockClock or other overrides
|
|
* don't affect continuation timeouts.
|
|
* @type {Function}
|
|
* @private
|
|
*/
|
|
goog.testing.ContinuationTestCase.Step.protectedClearTimeout_ =
|
|
window.clearTimeout;
|
|
|
|
|
|
/**
|
|
* A saved reference to window.setTimeout so that MockClock or other overrides
|
|
* don't affect continuation timeouts.
|
|
* @type {Function}
|
|
* @private
|
|
*/
|
|
goog.testing.ContinuationTestCase.Step.protectedSetTimeout_ = window.setTimeout;
|
|
|
|
|
|
/**
|
|
* Key to this step's timeout. If the step is waiting for an event, the timeout
|
|
* will be used as a kill timer. If the step is waiting
|
|
* @type {number}
|
|
* @private
|
|
*/
|
|
goog.testing.ContinuationTestCase.Step.prototype.timeout_;
|
|
|
|
|
|
/**
|
|
* Starts a timeout for this step. Each step may have only one timeout active at
|
|
* a time.
|
|
* @param {Function} func The function to call after the timeout.
|
|
* @param {number} duration The number of milliseconds to wait before invoking
|
|
* the function.
|
|
*/
|
|
goog.testing.ContinuationTestCase.Step.prototype.setTimeout =
|
|
function(func, duration) {
|
|
|
|
this.clearTimeout();
|
|
|
|
var setTimeout = goog.testing.ContinuationTestCase.Step.protectedSetTimeout_;
|
|
this.timeout_ = setTimeout(func, duration);
|
|
};
|
|
|
|
|
|
/**
|
|
* Clears the current timeout if it is active.
|
|
*/
|
|
goog.testing.ContinuationTestCase.Step.prototype.clearTimeout = function() {
|
|
if (this.timeout_) {
|
|
var clear = goog.testing.ContinuationTestCase.Step.protectedClearTimeout_;
|
|
|
|
clear(this.timeout_);
|
|
delete this.timeout_;
|
|
}
|
|
};
|