webdriverjs
Version:
A nodejs bindings implementation for selenium 2.0/webdriver
216 lines (180 loc) • 6.39 kB
JavaScript
'use strict';
/**
* RequestHandler
*/
var url = require('url'),
request = require('request'),
merge = require('deepmerge'),
errorCodes = require('./errorCodes');
module.exports = RequestHandler;
function RequestHandler(instance) {
var options = instance.options || {};
this.instance = instance;
this.sessionID = null;
this.startPath = '/wd/hub';
// Wdjs calls RequestHandler with `host` badly set
// A host is an hostname+port
if (options.host !== undefined) {
options.hostname = options.host;
delete options.host;
}
// default request options
this.defaultOptions = {
hostname: '127.0.0.1',
port: 4444,
protocol: 'http'
};
// add user specific attributes
this.defaultOptions = merge(this.defaultOptions, options);
// set auth from user and password configs
if(this.defaultOptions.user && this.defaultOptions.key) {
this.auth = {
user: this.defaultOptions.user,
pass: this.defaultOptions.key
};
delete this.defaultOptions.user;
delete this.defaultOptions.key;
}
};
/**
* set session ID for the next request
*
* @param {Object} response response data with header information
*/
RequestHandler.prototype.setSessionID = function(body,response,data) {
this.sessionID = body.sessionId;
// check if we got a session id
/* istanbul ignore next */
if(!this.sessionID) {
this.instance.eventHandler.emit('error', {
err: {
code: 'NOSESSIONID',
message: body.message
},
body: body,
requestOptions: this.fullRequestOptions,
response: response
});
return;
}
this.instance.eventHandler.emit('init', {
sessionID: this.sessionID,
options: body.value,
desiredCapabilities: data.desiredCapabilities
});
this.instance.logger.log('SET SESSION ID ' + this.sessionID);
};
/**
* merges default options with request options
*
* @param {Object} requestOptions request options
*/
RequestHandler.prototype.createOptions = function(requestOptions, data) {
var newOptions = {};
newOptions.uri = url.parse(
this.defaultOptions.protocol + '://' +
this.defaultOptions.hostname + ':' + this.defaultOptions.port +
this.startPath +
requestOptions.path.replace(':sessionId', this.sessionID || ''));
// send authentication credentials only when creating new session
if (requestOptions.path === '/session' && this.auth !== undefined) {
newOptions.auth = this.auth;
}
if (requestOptions.method) {
newOptions.method = requestOptions.method;
}
newOptions.json = true;
newOptions.followAllRedirects = true;
newOptions.headers = {
'Connection': 'keep-alive',
'Accept': 'application/json'
};
if (Object.keys(data).length > 0) {
var reqData = JSON.stringify(data);
newOptions.body = reqData;
newOptions.method = 'POST';
newOptions.headers = merge(newOptions.headers, {
'Content-Type': 'application/json; charset=UTF-8',
'Content-Length': Buffer.byteLength(JSON.stringify(data), 'UTF-8')
});
}
return newOptions;
};
/**
* creates a http request with its given options and send the protocol
* command to the webdriver server
*
* @param {Object} requestOptions defines url, method and other request options
* @param {Object} data contains request data
* @param {Function} callback gets fired if server got a response
*/
RequestHandler.prototype.create = function(requestOptions, data, callback) {
if (typeof requestOptions === 'string') {
requestOptions = {
path: requestOptions
}
}
if (typeof data === 'function') {
callback = data;
data = {};
}
this.fullRequestOptions = this.createOptions(requestOptions, data);
this.instance.eventHandler.emit('command', {
method: this.fullRequestOptions.method || 'GET',
uri: this.fullRequestOptions.uri,
data: data
});
request(this.fullRequestOptions, function(err, response, body) {
var error = null;
var makeError = require('./makeError');
if(err || (body && body.status !== 0)) {
this.instance.eventHandler.emit('error', {
err: err,
requestData: data,
requestOptions: this.fullRequestOptions,
response: response,
body: body
});
if(body) {
error = makeError({
status: body.status,
type: errorCodes[body.status] ? errorCodes[body.status].id : 'unknown',
message: errorCodes[body.status] ? errorCodes[body.status].message : 'unknown',
orgStatusMessage: body.value ? body.value.message : ''
});
} else {
error = makeError({
status: -1,
type: 'ECONNREFUSED',
message: 'Couldn\'t connect to selenium server',
orgStatusMessage: 'Couldn\'t connect to selenium server'
});
// TODO skip rest of driver commands
return callback(error);
}
}
// if we dont have a session id we set it here, unless we
// call commands that dont require session ids, for
// example /sessions. The call to /sessions is not
// connected to a session itself and it therefore doesnt
// require it
if(this.sessionID === null && this.fullRequestOptions.requiresSession !== false) {
this.setSessionID(body,response,data);
}
if(body === undefined) {
body = {
status: 0,
orgStatusMessage: errorCodes[0].message
};
}
this.instance.eventHandler.emit('result', {
requestData: data,
requestOptions: this.fullRequestOptions,
response: response,
body: body,
});
if (callback) {
callback(error, error ? null : body);
}
}.bind(this));
};