Skip to content

Commit

Permalink
[js] code clean-up/simplification
Browse files Browse the repository at this point in the history
  • Loading branch information
jleyba committed Nov 3, 2017
1 parent 5520ee7 commit 5bd212e
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 80 deletions.
128 changes: 55 additions & 73 deletions javascript/node/selenium-webdriver/lib/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ const cmd = require('./command');
const error = require('./error');
const logging = require('./logging');
const promise = require('./promise');
const Session = require('./session').Session;
const WebElement = require('./webdriver').WebElement;
const {Session} = require('./session');
const {WebElement} = require('./webdriver');

const {getAttribute, isDisplayed} = /** @suppress {undefinedVars|uselessCode} */(function() {
try {
Expand Down Expand Up @@ -145,7 +145,7 @@ function resource(method, path) { return {method: method, path: path}; }
var CommandSpec;


/** @typedef {function(!cmd.Command): !Promise<!cmd.Command>} */
/** @typedef {function(!cmd.Command): !cmd.Command} */
var CommandTransformer;


Expand All @@ -155,21 +155,17 @@ class InternalTypeError extends TypeError {}
/**
* @param {!cmd.Command} command The initial command.
* @param {Atom} atom The name of the atom to execute.
* @return {!Promise<!cmd.Command>} The transformed command to execute.
* @return {!cmd.Command} The transformed command to execute.
*/
function toExecuteAtomCommand(command, atom, ...params) {
return new Promise((resolve, reject) => {
if (typeof atom !== 'function') {
reject(new InternalTypeError('atom is not a function: ' + typeof atom));
return;
}
if (typeof atom !== 'function') {
throw new InternalTypeError('atom is not a function: ' + typeof atom);
}

let newCmd = new cmd.Command(cmd.Name.EXECUTE_SCRIPT)
.setParameter('sessionId', command.getParameter('sessionId'))
.setParameter('script', `return (${atom}).apply(null, arguments)`)
.setParameter('args', params.map(param => command.getParameter(param)));
resolve(newCmd);
});
return new cmd.Command(cmd.Name.EXECUTE_SCRIPT)
.setParameter('sessionId', command.getParameter('sessionId'))
.setParameter('script', `return (${atom}).apply(null, arguments)`)
.setParameter('args', params.map(param => command.getParameter(param)));
}


Expand Down Expand Up @@ -287,35 +283,13 @@ class Client {
}


const CLIENTS =
/** !WeakMap<!Executor, !(Client|IThenable<!Client>)> */new WeakMap;


/**
* Sends a request using the given executor.
* @param {!Executor} executor
* @param {!Request} request
* @return {!Promise<Response>}
*/
function doSend(executor, request) {
const client = CLIENTS.get(executor);
if (promise.isPromise(client)) {
return client.then(client => {
CLIENTS.set(executor, client);
return client.send(request);
});
} else {
return client.send(request);
}
}


/**
* @param {Map<string, CommandSpec>} customCommands
* A map of custom command definitions.
* @param {boolean} w3c Whether to use W3C command mappings.
* @param {!cmd.Command} command The command to resolve.
* @return {!Promise<!Request>} A promise that will resolve with the
* @return {!Request} A promise that will resolve with the
* command to execute.
*/
function buildRequest(customCommands, w3c, command) {
Expand All @@ -329,8 +303,8 @@ function buildRequest(customCommands, w3c, command) {
spec = W3C_COMMAND_MAP.get(command.getName());
if (typeof spec === 'function') {
LOG.finest(() => `Transforming command for W3C: ${command.getName()}`);
return spec(command)
.then(newCommand => buildRequest(customCommands, w3c, newCommand));
let newCommand = spec(command);
return buildRequest(customCommands, w3c, newCommand);
} else if (spec) {
return toHttpRequest(spec);
}
Expand All @@ -340,23 +314,26 @@ function buildRequest(customCommands, w3c, command) {
if (spec) {
return toHttpRequest(spec);
}
return Promise.reject(
new error.UnknownCommandError(
'Unrecognized command: ' + command.getName()));
throw new error.UnknownCommandError(
'Unrecognized command: ' + command.getName());

/**
* @param {CommandSpec} resource
* @return {!Promise<!Request>}
* @return {!Request}
*/
function toHttpRequest(resource) {
LOG.finest(() => `Building HTTP request: ${JSON.stringify(resource)}`);
let parameters = command.getParameters();
let path = buildPath(resource.path, parameters);
return Promise.resolve(new Request(resource.method, path, parameters));
return new Request(resource.method, path, parameters);
}
}


const CLIENTS =
/** !WeakMap<!Executor, !(Client|IThenable<!Client>)> */new WeakMap;


/**
* A command executor that communicates with the server using JSON over HTTP.
*
Expand Down Expand Up @@ -416,36 +393,41 @@ class Executor {
}

/** @override */
execute(command) {
async execute(command) {
let request = buildRequest(this.customCommands_, this.w3c, command);
return request.then(request => {
this.log_.finer(() => `>>> ${request.method} ${request.path}`);
return doSend(this, request).then(response => {
this.log_.finer(() => `>>>\n${request}\n<<<\n${response}`);

let httpResponse = /** @type {!Response} */(response);
let {isW3C, value} = parseHttpResponse(command, httpResponse);

if (command.getName() === cmd.Name.NEW_SESSION) {
if (!value || !value.sessionId) {
throw new error.WebDriverError(
`Unable to parse new session response: ${response.body}`);
}

// The remote end is a W3C compliant server if there is no `status`
// field in the response.
if (command.getName() === cmd.Name.NEW_SESSION) {
this.w3c = this.w3c || isW3C;
}

// No implementations use the `capabilities` key yet...
let capabilities = value.capabilities || value.value;
return new Session(value.sessionId, capabilities);
}
this.log_.finer(() => `>>> ${request.method} ${request.path}`);

let client = CLIENTS.get(this);
if (promise.isPromise(client)) {
client = await client;
CLIENTS.set(this, client);
}

let response = await client.send(request);
this.log_.finer(() => `>>>\n${request}\n<<<\n${response}`);

let httpResponse = /** @type {!Response} */(response);
let {isW3C, value} = parseHttpResponse(command, httpResponse);

if (command.getName() === cmd.Name.NEW_SESSION) {
if (!value || !value.sessionId) {
throw new error.WebDriverError(
`Unable to parse new session response: ${response.body}`);
}

// The remote end is a W3C compliant server if there is no `status`
// field in the response.
if (command.getName() === cmd.Name.NEW_SESSION) {
this.w3c = this.w3c || isW3C;
}

// No implementations use the `capabilities` key yet...
let capabilities = value.capabilities || value.value;
return new Session(
/** @type {{sessionId: string}} */(value).sessionId, capabilities);
}

return typeof value === 'undefined' ? null : value;
});
});
return typeof value === 'undefined' ? null : value;
}
}

Expand Down
5 changes: 5 additions & 0 deletions javascript/node/selenium-webdriver/lib/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ function suite(fn, options = undefined) {
// GLOBAL TEST SETUP


process.on('unhandledRejection', (reason) => {
console.error('Unhandled promise rejection:', reason);
});


if (/^1|true$/i.test(process.env['SELENIUM_VERBOSE'])) {
logging.installConsoleHandler();
logging.getLogger('webdriver.http').setLevel(logging.Level.ALL);
Expand Down
15 changes: 8 additions & 7 deletions javascript/node/selenium-webdriver/test/lib/http_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,20 +118,21 @@ describe('http', function() {
});
});

it('rejects commands missing URL parameters', function() {
it('rejects commands missing URL parameters', async function() {
let command =
new Command(CommandName.FIND_CHILD_ELEMENT).
setParameter('sessionId', 's123').
// Let this be missing: setParameter('id', {'ELEMENT': 'e456'}).
setParameter('using', 'id').
setParameter('value', 'foo');

assert.throws(
() => executor.execute(command),
function(err) {
return err instanceof error.InvalidArgumentError
&& 'Missing required parameter: id' === err.message;
});
try {
await executor.execute(command);
return Promise.reject(Error('should have thrown'));
} catch (err) {
assert.strictEqual(err.constructor, error.InvalidArgumentError);
assert.equal(err.message, 'Missing required parameter: id');
}
assert.ok(!send.called);
});

Expand Down

0 comments on commit 5bd212e

Please sign in to comment.