// Copyright 2007 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 A class representing a set of test functions to be run. * * Testing code should not have dependencies outside of goog.testing so as to * reduce the chance of masking missing dependencies. * * This file does not compile correctly with --collapse_properties. Use * --property_renaming=ALL_UNQUOTED instead. * */ goog.setTestOnly('goog.testing.TestCase'); goog.provide('goog.testing.TestCase'); goog.provide('goog.testing.TestCase.Error'); goog.provide('goog.testing.TestCase.Order'); goog.provide('goog.testing.TestCase.Result'); goog.provide('goog.testing.TestCase.Test'); goog.require('goog.Promise'); goog.require('goog.Thenable'); goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.dom'); goog.require('goog.dom.TagName'); goog.require('goog.json'); goog.require('goog.object'); goog.require('goog.testing.JsUnitException'); goog.require('goog.testing.asserts'); /** * A class representing a JsUnit test case. A TestCase is made up of a number * of test functions which can be run. Individual test cases can override the * following functions to set up their test environment: * - runTests - completely override the test's runner * - setUpPage - called before any of the test functions are run * - tearDownPage - called after all tests are finished * - setUp - called before each of the test functions * - tearDown - called after each of the test functions * - shouldRunTests - called before a test run, all tests are skipped if it * returns false. Can be used to disable tests on browsers * where they aren't expected to pass. *

* TestCase objects are usually constructed by inspecting the global environment * to discover functions that begin with the prefix test. * (See {@link #autoDiscoverLifecycle} and {@link #autoDiscoverTests}.) *

* *

Testing asychronous code with promises

* *

* In the simplest cases, the behavior that the developer wants to test * is synchronous, and the test functions exercising the behavior execute * synchronously. But TestCase can also be used to exercise asynchronous code * through the use of * promises. If a test function returns an object that has a * then method defined on it, the test framework switches to an * asynchronous execution strategy: the next test function will not begin * execution until the returned promise is resolved or rejected. Instead of * writing test assertions at the top level inside a test function, the test * author chains them on the end of the returned promise. For example: *

*
 *   function testPromiseBasedAPI() {
 *     return promiseBasedAPI().then(function(value) {
 *       // Will run when the promise resolves, and before the next
 *       // test function begins execution.
 *       assertEquals('foo', value.bar);
 *     });
 *   }
 * 
*

* Synchronous and asynchronous tests can be mixed in the same TestCase. * Test functions that return an object with a then method are * executed asynchronously, and all other test functions are executed * synchronously. While this is convenient for test authors (since it doesn't * require any explicit configuration for asynchronous tests), it can lead to * confusion if the test author forgets to return the promise from the test * function. For example: *

*
 *   function testPromiseBasedAPI() {
 *     // This test should never succeed.
 *     promiseBasedAPI().then(fail, fail);
 *     // Oops! The promise isn't returned to the framework,
 *     // so this test actually does succeed.
 *   }
 * 
*

* Since the test framework knows nothing about the promise created * in the test function, it will run the function synchronously, record * a success, and proceed immediately to the next test function. *

*

* Promises returned from test functions can time out. If a returned promise * is not resolved or rejected within {@link promiseTimeout} milliseconds, * the test framework rejects the promise without a timeout error message. * Test cases can configure the value of {@code promiseTimeout} by setting *

 *   goog.testing.TestCase.getActiveTestCase().promiseTimeout = ...
 * 
* in their {@code setUpPage} methods. *

* * @param {string=} opt_name The name of the test case, defaults to * 'Untitled Test Case'. * @constructor */ goog.testing.TestCase = function(opt_name) { /** * A name for the test case. * @type {string} * @private */ this.name_ = opt_name || 'Untitled Test Case'; /** * Array of test functions that can be executed. * @type {!Array} * @private */ this.tests_ = []; /** * Set of test names and/or indices to execute, or null if all tests should * be executed. * * Indices are included to allow automation tools to run a subset of the * tests without knowing the exact contents of the test file. * * Indices should only be used with SORTED ordering. * * Example valid values: *