wallet-core/node_modules/selenium-webdriver/testing/index.js
2016-11-03 01:33:53 +01:00

278 lines
7.7 KiB
JavaScript

// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you 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 Provides wrappers around the following global functions from
* [Mocha's BDD interface](https://github.com/mochajs/mocha):
*
* - after
* - afterEach
* - before
* - beforeEach
* - it
* - it.only
* - it.skip
* - xit
*
* The provided wrappers leverage the {@link webdriver.promise.ControlFlow}
* to simplify writing asynchronous tests:
*
* var By = require('selenium-webdriver').By,
* until = require('selenium-webdriver').until,
* firefox = require('selenium-webdriver/firefox'),
* test = require('selenium-webdriver/testing');
*
* test.describe('Google Search', function() {
* var driver;
*
* test.before(function() {
* driver = new firefox.Driver();
* });
*
* test.after(function() {
* driver.quit();
* });
*
* test.it('should append query to title', function() {
* 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);
* });
* });
*
* You may conditionally suppress a test function using the exported
* "ignore" function. If the provided predicate returns true, the attached
* test case will be skipped:
*
* test.ignore(maybe()).it('is flaky', function() {
* if (Math.random() < 0.5) throw Error();
* });
*
* function maybe() { return Math.random() < 0.5; }
*/
var promise = require('..').promise;
var flow = promise.controlFlow();
/**
* 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() {
if (arguments.length === 1) {
return globalFn(wrapArgument(arguments[0]));
} else if (arguments.length === 2) {
return globalFn(arguments[0], wrapArgument(arguments[1]));
} else {
throw Error('Invalid # arguments: ' + arguments.length);
}
};
}
function wrapArgument(value) {
if (typeof value === 'function') {
return makeAsyncTestFn(value);
}
return value;
}
/**
* Make a wrapper to invoke caller's test function, fn. Run the test function
* within a ControlFlow.
*
* Should preserve the semantics of Mocha's Runnable.prototype.run (See
* https://github.com/mochajs/mocha/blob/master/lib/runnable.js#L192)
*
* @param {Function} fn
* @return {Function}
*/
function makeAsyncTestFn(fn) {
var async = fn.length > 0; // if test function expects a callback, its "async"
var ret = /** @type {function(this: mocha.Context)}*/ (function(done) {
var runnable = this.runnable();
var mochaCallback = runnable.callback;
runnable.callback = function() {
flow.reset();
return mochaCallback.apply(this, arguments);
};
var testFn = fn.bind(this);
flow.execute(function controlFlowExecute() {
return new promise.Promise(function(fulfill, reject) {
if (async) {
// If testFn is async (it expects a done callback), resolve the promise of this
// test whenever that callback says to. Any promises returned from testFn are
// ignored.
testFn(function testFnDoneCallback(err) {
if (err) {
reject(err);
} else {
fulfill();
}
});
} else {
// Without a callback, testFn can return a promise, or it will
// be assumed to have completed synchronously
fulfill(testFn());
}
}, flow);
}, runnable.fullTitle()).then(seal(done), done);
});
ret.toString = function() {
return fn.toString();
};
return ret;
}
/**
* 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.
* @return {!Object} An object with wrapped versions of {@link #it()} and
* {@link #describe()} that ignore tests as indicated by the predicate.
*/
function ignore(predicateFn) {
var describe = wrap(exports.xdescribe, exports.describe);
describe.only = wrap(exports.xdescribe, exports.describe.only);
var it = wrap(exports.xit, exports.it);
it.only = wrap(exports.xit, exports.it.only);
return {
describe: describe,
it: it
};
function wrap(onSkip, onRun) {
return function(title, fn) {
if (predicateFn()) {
onSkip(title, fn);
} else {
onRun(title, fn);
}
};
}
}
// PUBLIC API
/**
* @return {!promise.ControlFlow} the control flow instance used by this module
* to coordinate test actions.
*/
exports.controlFlow = function(){
return flow;
};
/**
* 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.
*/
exports.describe = global.describe;
/**
* 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.
*/
exports.xdescribe = global.xdescribe;
exports.describe.skip = global.describe.skip;
/**
* Register a function to call after the current suite finishes.
* @param {function()} fn .
*/
exports.after = wrapped(global.after);
/**
* Register a function to call after each test in a suite.
* @param {function()} fn .
*/
exports.afterEach = wrapped(global.afterEach);
/**
* Register a function to call before the current suite starts.
* @param {function()} fn .
*/
exports.before = wrapped(global.before);
/**
* Register a function to call before each test in a suite.
* @param {function()} fn .
*/
exports.beforeEach = wrapped(global.beforeEach);
/**
* 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.
*/
exports.it = wrapped(global.it);
/**
* 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);
exports.ignore = ignore;