2014-11-10 19:51:40 -08:00
|
|
|
/**
|
|
|
|
|
* @license
|
|
|
|
|
* Copyright 2013 Selenium committers
|
|
|
|
|
* Copyright 2013 Software Freedom Conservancy
|
|
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
2013-03-05 21:03:26 -08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @fileoverview Provides wrappers around the following global functions from
|
2014-02-02 18:56:15 -08:00
|
|
|
* <a href="http://visionmedia.github.io/mocha/">Mocha's BDD interface</a>:
|
|
|
|
|
* <ul>
|
|
|
|
|
* <li>after
|
|
|
|
|
* <li>afterEach
|
|
|
|
|
* <li>before
|
|
|
|
|
* <li>beforeEach
|
|
|
|
|
* <li>it
|
|
|
|
|
* <li>it.only
|
|
|
|
|
* <li>it.skip
|
|
|
|
|
* <li>xit
|
|
|
|
|
* </ul>
|
2013-03-05 21:03:26 -08:00
|
|
|
*
|
2014-05-26 13:21:03 -07:00
|
|
|
* <p>The provided wrappers leverage the {@link webdriver.promise.ControlFlow}
|
|
|
|
|
* to simplify writing asynchronous tests:
|
2014-02-02 18:56:15 -08:00
|
|
|
* <pre><code>
|
2014-10-16 16:50:33 -07:00
|
|
|
* var By = require('selenium-webdriver').By,
|
|
|
|
|
* until = require('selenium-webdriver').until,
|
|
|
|
|
* firefox = require('selenium-webdriver/firefox'),
|
2013-03-05 21:03:26 -08:00
|
|
|
* test = require('selenium-webdriver/testing');
|
|
|
|
|
*
|
|
|
|
|
* test.describe('Google Search', function() {
|
2014-10-16 16:50:33 -07:00
|
|
|
* var driver;
|
2013-03-05 21:03:26 -08:00
|
|
|
*
|
|
|
|
|
* test.before(function() {
|
2014-10-16 16:50:33 -07:00
|
|
|
* driver = new firefox.Driver();
|
2013-03-05 21:03:26 -08:00
|
|
|
* });
|
|
|
|
|
*
|
|
|
|
|
* test.after(function() {
|
|
|
|
|
* driver.quit();
|
|
|
|
|
* });
|
|
|
|
|
*
|
|
|
|
|
* test.it('should append query to title', function() {
|
2014-10-16 16:50:33 -07:00
|
|
|
* driver.get('http://www.google.com/ncr');
|
|
|
|
|
* driver.findElement(By.name('q')).sendKeys('webdriver');
|
|
|
|
|
* driver.findElement(By.name('btnG')).click();
|
|
|
|
|
* driver.wait(until.titleIs('webdriver - Google Search'), 1000);
|
2013-03-05 21:03:26 -08:00
|
|
|
* });
|
|
|
|
|
* });
|
2014-02-02 18:56:15 -08:00
|
|
|
* </code></pre>
|
2013-03-05 21:03:26 -08:00
|
|
|
*
|
2014-02-02 18:56:15 -08:00
|
|
|
* <p>You may conditionally suppress a test function using the exported
|
2013-03-05 21:03:26 -08:00
|
|
|
* "ignore" function. If the provided predicate returns true, the attached
|
|
|
|
|
* test case will be skipped:
|
2014-02-02 18:56:15 -08:00
|
|
|
* <pre><code>
|
2013-03-05 21:03:26 -08:00
|
|
|
* test.ignore(maybe()).it('is flaky', function() {
|
|
|
|
|
* if (Math.random() < 0.5) throw Error();
|
|
|
|
|
* });
|
|
|
|
|
*
|
|
|
|
|
* function maybe() { return Math.random() < 0.5; }
|
2014-02-02 18:56:15 -08:00
|
|
|
* </code></pre>
|
2013-03-05 21:03:26 -08:00
|
|
|
*/
|
|
|
|
|
|
2014-05-26 13:21:03 -07:00
|
|
|
var promise = require('..').promise;
|
|
|
|
|
var flow = promise.controlFlow();
|
2013-03-05 21:03:26 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Wraps a function so that all passed arguments are ignored.
|
|
|
|
|
* @param {!Function} fn The function to wrap.
|
|
|
|
|
* @return {!Function} The wrapped function.
|
|
|
|
|
*/
|
|
|
|
|
function seal(fn) {
|
|
|
|
|
return function() {
|
|
|
|
|
fn();
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Wraps a function on Mocha's BDD interface so it runs inside a
|
|
|
|
|
* webdriver.promise.ControlFlow and waits for the flow to complete before
|
|
|
|
|
* continuing.
|
|
|
|
|
* @param {!Function} globalFn The function to wrap.
|
|
|
|
|
* @return {!Function} The new function.
|
|
|
|
|
*/
|
|
|
|
|
function wrapped(globalFn) {
|
|
|
|
|
return function() {
|
2014-07-08 10:47:54 -04:00
|
|
|
if (arguments.length === 1) {
|
|
|
|
|
return globalFn(asyncTestFn(arguments[0]));
|
|
|
|
|
}
|
|
|
|
|
else if (arguments.length === 2) {
|
|
|
|
|
return globalFn(arguments[0], asyncTestFn(arguments[1]));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
throw Error('Invalid # arguments: ' + arguments.length);
|
2013-03-05 21:03:26 -08:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function asyncTestFn(fn) {
|
2014-05-13 10:58:22 -07:00
|
|
|
var ret = function(done) {
|
2014-07-08 10:47:54 -04:00
|
|
|
function cleanupBeforeCallback() {
|
|
|
|
|
flow.reset();
|
|
|
|
|
return cleanupBeforeCallback.mochaCallback.apply(this, arguments);
|
2014-03-26 10:08:22 -07:00
|
|
|
}
|
2014-07-08 10:47:54 -04:00
|
|
|
// We set this as an attribute of the callback function to allow us to
|
|
|
|
|
// test this properly.
|
|
|
|
|
cleanupBeforeCallback.mochaCallback = this.runnable().callback;
|
|
|
|
|
|
|
|
|
|
this.runnable().callback = cleanupBeforeCallback;
|
|
|
|
|
|
|
|
|
|
var testFn = fn.bind(this);
|
|
|
|
|
flow.execute(function() {
|
|
|
|
|
var done = promise.defer();
|
|
|
|
|
promise.asap(testFn(done.reject), done.fulfill, done.reject);
|
|
|
|
|
return done.promise;
|
|
|
|
|
}).then(seal(done), done);
|
2013-03-05 21:03:26 -08:00
|
|
|
};
|
2014-05-13 10:58:22 -07:00
|
|
|
|
|
|
|
|
ret.toString = function() {
|
|
|
|
|
return fn.toString();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return ret;
|
2013-03-05 21:03:26 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Ignores the test chained to this function if the provided predicate returns
|
|
|
|
|
* true.
|
|
|
|
|
* @param {function(): boolean} predicateFn A predicate to call to determine
|
|
|
|
|
* if the test should be suppressed. This function MUST be synchronous.
|
2014-02-02 18:56:15 -08:00
|
|
|
* @return {!Object} An object with wrapped versions of {@link #it()} and
|
|
|
|
|
* {@link #describe()} that ignore tests as indicated by the predicate.
|
2013-03-05 21:03:26 -08:00
|
|
|
*/
|
|
|
|
|
function ignore(predicateFn) {
|
2013-07-04 19:46:17 -07:00
|
|
|
var describe = wrap(exports.xdescribe, exports.describe);
|
|
|
|
|
describe.only = wrap(exports.xdescribe, exports.describe.only);
|
2013-03-05 21:03:26 -08:00
|
|
|
|
2013-07-04 19:46:17 -07:00
|
|
|
var it = wrap(exports.xit, exports.it);
|
|
|
|
|
it.only = wrap(exports.xit, exports.it.only);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
describe: describe,
|
|
|
|
|
it: it
|
2013-03-05 21:03:26 -08:00
|
|
|
};
|
|
|
|
|
|
2013-07-04 19:46:17 -07:00
|
|
|
function wrap(onSkip, onRun) {
|
|
|
|
|
return function(title, fn) {
|
|
|
|
|
if (predicateFn()) {
|
|
|
|
|
onSkip(title, fn);
|
|
|
|
|
} else {
|
|
|
|
|
onRun(title, fn);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
2013-06-22 10:40:38 -07:00
|
|
|
}
|
2013-03-05 21:03:26 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
// PUBLIC API
|
|
|
|
|
|
2014-02-02 18:56:15 -08:00
|
|
|
/**
|
|
|
|
|
* Registers a new test suite.
|
|
|
|
|
* @param {string} name The suite name.
|
|
|
|
|
* @param {function()=} fn The suite function, or {@code undefined} to define
|
|
|
|
|
* a pending test suite.
|
|
|
|
|
*/
|
2013-03-05 21:03:26 -08:00
|
|
|
exports.describe = global.describe;
|
2014-02-02 18:56:15 -08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Defines a suppressed test suite.
|
|
|
|
|
* @param {string} name The suite name.
|
|
|
|
|
* @param {function()=} fn The suite function, or {@code undefined} to define
|
|
|
|
|
* a pending test suite.
|
|
|
|
|
*/
|
2013-03-05 21:03:26 -08:00
|
|
|
exports.xdescribe = global.xdescribe;
|
2013-07-04 19:46:17 -07:00
|
|
|
exports.describe.skip = global.describe.skip;
|
2013-03-05 21:03:26 -08:00
|
|
|
|
2014-02-02 18:56:15 -08:00
|
|
|
/**
|
|
|
|
|
* Register a function to call after the current suite finishes.
|
|
|
|
|
* @param {function()} fn .
|
|
|
|
|
*/
|
2013-03-12 20:04:46 -07:00
|
|
|
exports.after = wrapped(global.after);
|
2014-02-02 18:56:15 -08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Register a function to call after each test in a suite.
|
|
|
|
|
* @param {function()} fn .
|
|
|
|
|
*/
|
2013-03-12 20:04:46 -07:00
|
|
|
exports.afterEach = wrapped(global.afterEach);
|
2014-02-02 18:56:15 -08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Register a function to call before the current suite starts.
|
|
|
|
|
* @param {function()} fn .
|
|
|
|
|
*/
|
2013-03-12 20:04:46 -07:00
|
|
|
exports.before = wrapped(global.before);
|
2014-02-02 18:56:15 -08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Register a function to call before each test in a suite.
|
|
|
|
|
* @param {function()} fn .
|
|
|
|
|
*/
|
2013-03-12 20:04:46 -07:00
|
|
|
exports.beforeEach = wrapped(global.beforeEach);
|
|
|
|
|
|
2014-02-02 18:56:15 -08:00
|
|
|
/**
|
|
|
|
|
* Add a test to the current suite.
|
|
|
|
|
* @param {string} name The test name.
|
|
|
|
|
* @param {function()=} fn The test function, or {@code undefined} to define
|
|
|
|
|
* a pending test case.
|
|
|
|
|
*/
|
2013-03-12 20:04:46 -07:00
|
|
|
exports.it = wrapped(global.it);
|
2014-02-02 18:56:15 -08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* An alias for {@link #it()} that flags the test as the only one that should
|
|
|
|
|
* be run within the current suite.
|
|
|
|
|
* @param {string} name The test name.
|
|
|
|
|
* @param {function()=} fn The test function, or {@code undefined} to define
|
|
|
|
|
* a pending test case.
|
|
|
|
|
*/
|
|
|
|
|
exports.iit = exports.it.only = wrapped(global.it.only);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Adds a test to the current suite while suppressing it so it is not run.
|
|
|
|
|
* @param {string} name The test name.
|
|
|
|
|
* @param {function()=} fn The test function, or {@code undefined} to define
|
|
|
|
|
* a pending test case.
|
|
|
|
|
*/
|
|
|
|
|
exports.xit = exports.it.skip = wrapped(global.xit);
|
2013-03-05 21:03:26 -08:00
|
|
|
|
|
|
|
|
exports.ignore = ignore;
|