diff options
author | Florian Dold <florian.dold@gmail.com> | 2016-11-03 01:33:53 +0100 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2016-11-03 01:33:53 +0100 |
commit | d1291f67551c58168af43698a359cb5ddfd266b0 (patch) | |
tree | 55a13ed29fe1915e3f42f1b1b7038dafa2e975a7 /node_modules/selenium-webdriver/testing/index.js | |
parent | d0a0695fb5d34996850723f7d4b1b59c3df909c2 (diff) |
node_modules
Diffstat (limited to 'node_modules/selenium-webdriver/testing/index.js')
-rw-r--r-- | node_modules/selenium-webdriver/testing/index.js | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/node_modules/selenium-webdriver/testing/index.js b/node_modules/selenium-webdriver/testing/index.js new file mode 100644 index 000000000..0e9d06232 --- /dev/null +++ b/node_modules/selenium-webdriver/testing/index.js @@ -0,0 +1,277 @@ +// 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; |