Skip to content

Commit

Permalink
[js] Migrate the webdriver.Command* types to a node module
Browse files Browse the repository at this point in the history
  • Loading branch information
jleyba committed Jan 25, 2016
1 parent 28843bb commit 428398f
Show file tree
Hide file tree
Showing 12 changed files with 376 additions and 122 deletions.
2 changes: 2 additions & 0 deletions javascript/node/selenium-webdriver/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ the selenium-webdriver package README.
* Changed some `io` operations to use native promises.
* Changed `webdriver.CommandExecutor#execute()` and `HttpClient` to return
promises instead of using callback passing.
* Migrated the `webdriver.Command*` types from using the Closure Library to the
new `lib/command` module.
* API documentation is no longer distributed with the npm package, but remains
available at <http://seleniumhq.github.io/selenium/docs/api/javascript/>
* Rewrote the `error` module to export an Error subtype for each type of error
Expand Down
5 changes: 3 additions & 2 deletions javascript/node/selenium-webdriver/chrome.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ var webdriver = require('./index'),
executors = require('./executors'),
http = require('./http'),
io = require('./io'),
command = require('./lib/command'),
portprober = require('./net/portprober'),
remote = require('./remote');

Expand All @@ -146,7 +147,7 @@ var Command = {
/**
* Creates a command executor with support for ChromeDriver's custom commands.
* @param {!webdriver.promise.Promise<string>} url The server's URL.
* @return {!webdriver.CommandExecutor} The new command executor.
* @return {!command.Executor} The new command executor.
*/
function createExecutor(url) {
return new executors.DeferredExecutor(url.then(function(url) {
Expand Down Expand Up @@ -833,7 +834,7 @@ Driver.prototype.setFileDetector = function() {
*/
Driver.prototype.launchApp = function(id) {
return this.schedule(
new webdriver.Command(Command.LAUNCH_APP).setParameter('id', id),
new command.Command(Command.LAUNCH_APP).setParameter('id', id),
'Driver.launchApp()');
};

Expand Down
38 changes: 21 additions & 17 deletions javascript/node/selenium-webdriver/executors.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,35 @@
// under the License.

/**
* @fileoverview Various utilities for working with
* {@link webdriver.CommandExecutor} implementations.
* @fileoverview Various utilities for working with {@link ./command.Executor}
* implementations.
*/

'use strict';

var HttpClient = require('./http').HttpClient,
HttpExecutor = require('./http').Executor,
promise = require('./lib/_base').require('webdriver.promise');



/**
* Wraps a promised {@link webdriver.CommandExecutor}, ensuring no commands
* are executed until the wrapped executor has been fully built.
* @param {!webdriver.promise.Promise.<!webdriver.CommandExecutor>} delegate The
* promised delegate.
* @constructor
* @implements {webdriver.CommandExecutor}
* Wraps a promised {@link ./lib/command.Executor}, ensuring no commands are
* executed until the wrapped executor has been fully built.
* @implements {./lib/command.Executor}
*/
var DeferredExecutor = function(delegate) {

/** @override */
this.execute = function(command) {
return delegate.then(executor => executor.execute(command));
};
};
class DeferredExecutor {
/**
* @param {!webdriver.promise.Promise<!./lib/command.Executor>} delegate
* The promised delegate.
*/
constructor(delegate) {
/** @override */
this.execute = function(command) {
return delegate.then(executor => executor.execute(command));
};
}
}


// PUBLIC API
Expand All @@ -50,11 +54,11 @@ exports.DeferredExecutor = DeferredExecutor;

/**
* Creates a command executor that uses WebDriver's JSON wire protocol.
* @param {(string|!webdriver.promise.Promise.<string>)} url The server's URL,
* @param {(string|!webdriver.promise.Promise<string>)} url The server's URL,
* or a promise that will resolve to that URL.
* @param {string=} opt_proxy (optional) The URL of the HTTP proxy for the
* client to use.
* @returns {!webdriver.CommandExecutor} The new command executor.
* @returns {!./lib/command.Executor} The new command executor.
*/
exports.createExecutor = function(url, opt_proxy) {
return new DeferredExecutor(promise.when(url, function(url) {
Expand Down
160 changes: 80 additions & 80 deletions javascript/node/selenium-webdriver/http/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
// under the License.

/**
* @fileoverview Defines a {@link webdriver.CommandExecutor} that communicates
* with a remote end using HTTP + JSON.
* @fileoverview Defines an {@linkplain cmd.Executor command executor} that
* communicates with a remote end using HTTP + JSON.
*/

'use strict';
Expand All @@ -27,7 +27,7 @@ const url = require('url');

const error = require('../error');
const base = require('../lib/_base');
const CName = base.require('webdriver.CommandName');
const cmd = require('../lib/command');
const logging = base.require('webdriver.logging');


Expand Down Expand Up @@ -113,83 +113,83 @@ function get(path) { return resource('GET', path); }
function resource(method, path) { return {method: method, path: path}; }


/** @const {!Map<CName, {method: string, path: string}>} */
/** @const {!Map<cmd.Name, {method: string, path: string}>} */
const COMMAND_MAP = new Map([
[CName.GET_SERVER_STATUS, get('/status')],
[CName.NEW_SESSION, post('/session')],
[CName.GET_SESSIONS, get('/sessions')],
[CName.DESCRIBE_SESSION, get('/session/:sessionId')],
[CName.QUIT, del('/session/:sessionId')],
[CName.CLOSE, del('/session/:sessionId/window')],
[CName.GET_CURRENT_WINDOW_HANDLE, get('/session/:sessionId/window_handle')],
[CName.GET_WINDOW_HANDLES, get('/session/:sessionId/window_handles')],
[CName.GET_CURRENT_URL, get('/session/:sessionId/url')],
[CName.GET, post('/session/:sessionId/url')],
[CName.GO_BACK, post('/session/:sessionId/back')],
[CName.GO_FORWARD, post('/session/:sessionId/forward')],
[CName.REFRESH, post('/session/:sessionId/refresh')],
[CName.ADD_COOKIE, post('/session/:sessionId/cookie')],
[CName.GET_ALL_COOKIES, get('/session/:sessionId/cookie')],
[CName.DELETE_ALL_COOKIES, del('/session/:sessionId/cookie')],
[CName.DELETE_COOKIE, del('/session/:sessionId/cookie/:name')],
[CName.FIND_ELEMENT, post('/session/:sessionId/element')],
[CName.FIND_ELEMENTS, post('/session/:sessionId/elements')],
[CName.GET_ACTIVE_ELEMENT, post('/session/:sessionId/element/active')],
[CName.FIND_CHILD_ELEMENT, post('/session/:sessionId/element/:id/element')],
[CName.FIND_CHILD_ELEMENTS, post('/session/:sessionId/element/:id/elements')],
[CName.CLEAR_ELEMENT, post('/session/:sessionId/element/:id/clear')],
[CName.CLICK_ELEMENT, post('/session/:sessionId/element/:id/click')],
[CName.SEND_KEYS_TO_ELEMENT, post('/session/:sessionId/element/:id/value')],
[CName.SUBMIT_ELEMENT, post('/session/:sessionId/element/:id/submit')],
[CName.GET_ELEMENT_TEXT, get('/session/:sessionId/element/:id/text')],
[CName.GET_ELEMENT_TAG_NAME, get('/session/:sessionId/element/:id/name')],
[CName.IS_ELEMENT_SELECTED, get('/session/:sessionId/element/:id/selected')],
[CName.IS_ELEMENT_ENABLED, get('/session/:sessionId/element/:id/enabled')],
[CName.IS_ELEMENT_DISPLAYED, get('/session/:sessionId/element/:id/displayed')],
[CName.GET_ELEMENT_LOCATION, get('/session/:sessionId/element/:id/location')],
[CName.GET_ELEMENT_SIZE, get('/session/:sessionId/element/:id/size')],
[CName.GET_ELEMENT_ATTRIBUTE, get('/session/:sessionId/element/:id/attribute/:name')],
[CName.GET_ELEMENT_VALUE_OF_CSS_PROPERTY, get('/session/:sessionId/element/:id/css/:propertyName')],
[CName.ELEMENT_EQUALS, get('/session/:sessionId/element/:id/equals/:other')],
[CName.TAKE_ELEMENT_SCREENSHOT, get('/session/:sessionId/element/:id/screenshot')],
[CName.SWITCH_TO_WINDOW, post('/session/:sessionId/window')],
[CName.MAXIMIZE_WINDOW, post('/session/:sessionId/window/:windowHandle/maximize')],
[CName.GET_WINDOW_POSITION, get('/session/:sessionId/window/:windowHandle/position')],
[CName.SET_WINDOW_POSITION, post('/session/:sessionId/window/:windowHandle/position')],
[CName.GET_WINDOW_SIZE, get('/session/:sessionId/window/:windowHandle/size')],
[CName.SET_WINDOW_SIZE, post('/session/:sessionId/window/:windowHandle/size')],
[CName.SWITCH_TO_FRAME, post('/session/:sessionId/frame')],
[CName.GET_PAGE_SOURCE, get('/session/:sessionId/source')],
[CName.GET_TITLE, get('/session/:sessionId/title')],
[CName.EXECUTE_SCRIPT, post('/session/:sessionId/execute')],
[CName.EXECUTE_ASYNC_SCRIPT, post('/session/:sessionId/execute_async')],
[CName.SCREENSHOT, get('/session/:sessionId/screenshot')],
[CName.SET_TIMEOUT, post('/session/:sessionId/timeouts')],
[CName.SET_SCRIPT_TIMEOUT, post('/session/:sessionId/timeouts/async_script')],
[CName.IMPLICITLY_WAIT, post('/session/:sessionId/timeouts/implicit_wait')],
[CName.MOVE_TO, post('/session/:sessionId/moveto')],
[CName.CLICK, post('/session/:sessionId/click')],
[CName.DOUBLE_CLICK, post('/session/:sessionId/doubleclick')],
[CName.MOUSE_DOWN, post('/session/:sessionId/buttondown')],
[CName.MOUSE_UP, post('/session/:sessionId/buttonup')],
[CName.MOVE_TO, post('/session/:sessionId/moveto')],
[CName.SEND_KEYS_TO_ACTIVE_ELEMENT, post('/session/:sessionId/keys')],
[CName.TOUCH_SINGLE_TAP, post('/session/:sessionId/touch/click')],
[CName.TOUCH_DOUBLE_TAP, post('/session/:sessionId/touch/doubleclick')],
[CName.TOUCH_DOWN, post('/session/:sessionId/touch/down')],
[CName.TOUCH_UP, post('/session/:sessionId/touch/up')],
[CName.TOUCH_MOVE, post('/session/:sessionId/touch/move')],
[CName.TOUCH_SCROLL, post('/session/:sessionId/touch/scroll')],
[CName.TOUCH_LONG_PRESS, post('/session/:sessionId/touch/longclick')],
[CName.TOUCH_FLICK, post('/session/:sessionId/touch/flick')],
[CName.ACCEPT_ALERT, post('/session/:sessionId/accept_alert')],
[CName.DISMISS_ALERT, post('/session/:sessionId/dismiss_alert')],
[CName.GET_ALERT_TEXT, get('/session/:sessionId/alert_text')],
[CName.SET_ALERT_TEXT, post('/session/:sessionId/alert_text')],
[CName.GET_LOG, post('/session/:sessionId/log')],
[CName.GET_AVAILABLE_LOG_TYPES, get('/session/:sessionId/log/types')],
[CName.GET_SESSION_LOGS, post('/logs')],
[CName.UPLOAD_FILE, post('/session/:sessionId/file')],
[cmd.Name.GET_SERVER_STATUS, get('/status')],
[cmd.Name.NEW_SESSION, post('/session')],
[cmd.Name.GET_SESSIONS, get('/sessions')],
[cmd.Name.DESCRIBE_SESSION, get('/session/:sessionId')],
[cmd.Name.QUIT, del('/session/:sessionId')],
[cmd.Name.CLOSE, del('/session/:sessionId/window')],
[cmd.Name.GET_CURRENT_WINDOW_HANDLE, get('/session/:sessionId/window_handle')],
[cmd.Name.GET_WINDOW_HANDLES, get('/session/:sessionId/window_handles')],
[cmd.Name.GET_CURRENT_URL, get('/session/:sessionId/url')],
[cmd.Name.GET, post('/session/:sessionId/url')],
[cmd.Name.GO_BACK, post('/session/:sessionId/back')],
[cmd.Name.GO_FORWARD, post('/session/:sessionId/forward')],
[cmd.Name.REFRESH, post('/session/:sessionId/refresh')],
[cmd.Name.ADD_COOKIE, post('/session/:sessionId/cookie')],
[cmd.Name.GET_ALL_COOKIES, get('/session/:sessionId/cookie')],
[cmd.Name.DELETE_ALL_COOKIES, del('/session/:sessionId/cookie')],
[cmd.Name.DELETE_COOKIE, del('/session/:sessionId/cookie/:name')],
[cmd.Name.FIND_ELEMENT, post('/session/:sessionId/element')],
[cmd.Name.FIND_ELEMENTS, post('/session/:sessionId/elements')],
[cmd.Name.GET_ACTIVE_ELEMENT, post('/session/:sessionId/element/active')],
[cmd.Name.FIND_CHILD_ELEMENT, post('/session/:sessionId/element/:id/element')],
[cmd.Name.FIND_CHILD_ELEMENTS, post('/session/:sessionId/element/:id/elements')],
[cmd.Name.CLEAR_ELEMENT, post('/session/:sessionId/element/:id/clear')],
[cmd.Name.CLICK_ELEMENT, post('/session/:sessionId/element/:id/click')],
[cmd.Name.SEND_KEYS_TO_ELEMENT, post('/session/:sessionId/element/:id/value')],
[cmd.Name.SUBMIT_ELEMENT, post('/session/:sessionId/element/:id/submit')],
[cmd.Name.GET_ELEMENT_TEXT, get('/session/:sessionId/element/:id/text')],
[cmd.Name.GET_ELEMENT_TAG_NAME, get('/session/:sessionId/element/:id/name')],
[cmd.Name.IS_ELEMENT_SELECTED, get('/session/:sessionId/element/:id/selected')],
[cmd.Name.IS_ELEMENT_ENABLED, get('/session/:sessionId/element/:id/enabled')],
[cmd.Name.IS_ELEMENT_DISPLAYED, get('/session/:sessionId/element/:id/displayed')],
[cmd.Name.GET_ELEMENT_LOCATION, get('/session/:sessionId/element/:id/location')],
[cmd.Name.GET_ELEMENT_SIZE, get('/session/:sessionId/element/:id/size')],
[cmd.Name.GET_ELEMENT_ATTRIBUTE, get('/session/:sessionId/element/:id/attribute/:name')],
[cmd.Name.GET_ELEMENT_VALUE_OF_CSS_PROPERTY, get('/session/:sessionId/element/:id/css/:propertyName')],
[cmd.Name.ELEMENT_EQUALS, get('/session/:sessionId/element/:id/equals/:other')],
[cmd.Name.TAKE_ELEMENT_SCREENSHOT, get('/session/:sessionId/element/:id/screenshot')],
[cmd.Name.SWITCH_TO_WINDOW, post('/session/:sessionId/window')],
[cmd.Name.MAXIMIZE_WINDOW, post('/session/:sessionId/window/:windowHandle/maximize')],
[cmd.Name.GET_WINDOW_POSITION, get('/session/:sessionId/window/:windowHandle/position')],
[cmd.Name.SET_WINDOW_POSITION, post('/session/:sessionId/window/:windowHandle/position')],
[cmd.Name.GET_WINDOW_SIZE, get('/session/:sessionId/window/:windowHandle/size')],
[cmd.Name.SET_WINDOW_SIZE, post('/session/:sessionId/window/:windowHandle/size')],
[cmd.Name.SWITCH_TO_FRAME, post('/session/:sessionId/frame')],
[cmd.Name.GET_PAGE_SOURCE, get('/session/:sessionId/source')],
[cmd.Name.GET_TITLE, get('/session/:sessionId/title')],
[cmd.Name.EXECUTE_SCRIPT, post('/session/:sessionId/execute')],
[cmd.Name.EXECUTE_ASYNC_SCRIPT, post('/session/:sessionId/execute_async')],
[cmd.Name.SCREENSHOT, get('/session/:sessionId/screenshot')],
[cmd.Name.SET_TIMEOUT, post('/session/:sessionId/timeouts')],
[cmd.Name.SET_SCRIPT_TIMEOUT, post('/session/:sessionId/timeouts/async_script')],
[cmd.Name.IMPLICITLY_WAIT, post('/session/:sessionId/timeouts/implicit_wait')],
[cmd.Name.MOVE_TO, post('/session/:sessionId/moveto')],
[cmd.Name.CLICK, post('/session/:sessionId/click')],
[cmd.Name.DOUBLE_CLICK, post('/session/:sessionId/doubleclick')],
[cmd.Name.MOUSE_DOWN, post('/session/:sessionId/buttondown')],
[cmd.Name.MOUSE_UP, post('/session/:sessionId/buttonup')],
[cmd.Name.MOVE_TO, post('/session/:sessionId/moveto')],
[cmd.Name.SEND_KEYS_TO_ACTIVE_ELEMENT, post('/session/:sessionId/keys')],
[cmd.Name.TOUCH_SINGLE_TAP, post('/session/:sessionId/touch/click')],
[cmd.Name.TOUCH_DOUBLE_TAP, post('/session/:sessionId/touch/doubleclick')],
[cmd.Name.TOUCH_DOWN, post('/session/:sessionId/touch/down')],
[cmd.Name.TOUCH_UP, post('/session/:sessionId/touch/up')],
[cmd.Name.TOUCH_MOVE, post('/session/:sessionId/touch/move')],
[cmd.Name.TOUCH_SCROLL, post('/session/:sessionId/touch/scroll')],
[cmd.Name.TOUCH_LONG_PRESS, post('/session/:sessionId/touch/longclick')],
[cmd.Name.TOUCH_FLICK, post('/session/:sessionId/touch/flick')],
[cmd.Name.ACCEPT_ALERT, post('/session/:sessionId/accept_alert')],
[cmd.Name.DISMISS_ALERT, post('/session/:sessionId/dismiss_alert')],
[cmd.Name.GET_ALERT_TEXT, get('/session/:sessionId/alert_text')],
[cmd.Name.SET_ALERT_TEXT, post('/session/:sessionId/alert_text')],
[cmd.Name.GET_LOG, post('/session/:sessionId/log')],
[cmd.Name.GET_AVAILABLE_LOG_TYPES, get('/session/:sessionId/log/types')],
[cmd.Name.GET_SESSION_LOGS, post('/logs')],
[cmd.Name.UPLOAD_FILE, post('/session/:sessionId/file')],
]);


Expand Down Expand Up @@ -363,7 +363,7 @@ function sendRequest(options, onOk, onError, opt_data, opt_proxy) {

/**
* A command executor that communicates with the server using HTTP + JSON.
* @implements {webdriver.CommandExecutor}
* @implements {cmd.Executor}
*/
class Executor {
/**
Expand Down
4 changes: 2 additions & 2 deletions javascript/node/selenium-webdriver/http/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ var base = require('../lib/_base'),
Executor = require('./index').Executor,
HttpClient = require('./index').HttpClient,
HttpRequest = require('./index').Request,
Command = base.require('webdriver.Command'),
CommandName = base.require('webdriver.CommandName'),
Command = require('../lib/command').Command,
CommandName = require('../lib/command').Name,
promise = base.require('webdriver.promise');


Expand Down
13 changes: 2 additions & 11 deletions javascript/node/selenium-webdriver/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@
* public API and provides convenience assessors to certain sub-modules.
*/

var base = require('./lib/_base');
var builder = require('./builder');
var error = require('./error');
var base = require('./lib/_base');
var command = require('./lib/command');


// NOTE: the remainder of this file is nasty and verbose, but the annotations
Expand All @@ -45,10 +46,6 @@ exports.By = require('./lib/by').By;
exports.Capabilities = base.require('webdriver.Capabilities');


/** @type {function(new: webdriver.Command)} */
exports.Command = base.require('webdriver.Command');


/** @type {function(new: webdriver.EventEmitter)} */
exports.EventEmitter = base.require('webdriver.EventEmitter');

Expand Down Expand Up @@ -99,12 +96,6 @@ exports.WebElementPromise = base.require('webdriver.WebElementPromise');
}));


/** @type {webdriver.CommandName.} */
(exports.__defineGetter__('CommandName', function() {
return base.require('webdriver.CommandName');
}));


/** @type {webdriver.Key.} */
(exports.__defineGetter__('Key', function() {
return base.require('webdriver.Key');
Expand Down
15 changes: 14 additions & 1 deletion javascript/node/selenium-webdriver/lib/_base.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,12 @@ function Context(opt_configureForTesting) {
},
CLOSURE_NO_DEPS: !isDevMode(),
CLOSURE_UNCOMPILED_DEFINES: {'goog.json.USE_NATIVE_JSON': true},
goog: {}
goog: {},
webdriver: {
get Command() { return require('./command').Command; },
get CommandName() { return require('./command').Name; }
// get CommandExecutor() { return require('./command').Executor; }
}
});
closure.window = closure.top = closure;

Expand All @@ -125,6 +130,14 @@ function Context(opt_configureForTesting) {
loadScript(CLOSURE_BASE_FILE_PATH);
loadScript(DEPS_FILE_PATH);

let provide = closure.goog.provide;
closure.goog.provide = function(symbol) {
if (symbol.startsWith('webdriver.Command')) {
return;
}
provide(symbol);
};

// Redefine retrieveAndExecModule_ to load modules. Closure's version
// assumes XMLHttpRequest is defined (and by extension that scripts
// are being loaded from a server).
Expand Down
Loading

0 comments on commit 428398f

Please sign in to comment.