mirror of
https://github.com/sstent/node.git
synced 2026-01-26 23:22:28 +00:00
317 lines
9.1 KiB
JavaScript
317 lines
9.1 KiB
JavaScript
var http = require('http')
|
|
, __slice = Array.prototype.slice;
|
|
|
|
var strip = function strip(str) {
|
|
var x = [];
|
|
for (var i = 0; i < str.length; i++) {
|
|
if (str.charCodeAt(i)) {
|
|
x.push(str.charAt(i));
|
|
}
|
|
}
|
|
return x.join('');
|
|
};
|
|
|
|
var newError = function(opts)
|
|
{
|
|
var err = new Error();
|
|
for (var k in opts) {
|
|
err[k] = opts[k]
|
|
}
|
|
// nicer error output
|
|
err.inspect = function() {
|
|
var res = "";
|
|
for (var k in this) {
|
|
var _this = this;
|
|
(function() {
|
|
var v = _this[k];
|
|
if (typeof v === 'object') {
|
|
if ((v["class"] != null) && v["class"].match(/org.openqa.selenium.remote.Response/)) {
|
|
// for selenium classes, hidding long fields or field with
|
|
// duplicate information
|
|
var vAsStr = JSON.stringify(v, function(key, value) {
|
|
if (key === 'screen' || key === 'stackTrace' || key === 'buildInformation' || key === 'localizedMessage') {
|
|
return '[hidden]';
|
|
} else {
|
|
return value;
|
|
}
|
|
}, " ");
|
|
res = res + k + ": " + vAsStr + "\n";
|
|
} else {
|
|
// for other objects making sure output is not too long
|
|
var vAsStr = JSON.stringify(v, undefined, " ");
|
|
var maxLength = 1000;
|
|
if (vAsStr.length > maxLength) {
|
|
vAsStr = vAsStr.substr(0, maxLength) + "\n...";
|
|
}
|
|
res = res + k + ": " + vAsStr + "\n";
|
|
}
|
|
} else if (typeof v != 'function')
|
|
{
|
|
// printing non object types without modif
|
|
res = res + k + ": " + v + "\n";
|
|
}
|
|
})();
|
|
};
|
|
return res;
|
|
};
|
|
return err;
|
|
};
|
|
|
|
var isWebDriverException = function(res) {
|
|
var _ref;
|
|
if ((typeof res !== "undefined" && res !== null ?
|
|
(_ref = res["class"]) != null ? _ref.indexOf('WebDriverException') :
|
|
void 0 : void 0) > 0) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// just calls the callback when there is no result
|
|
var simpleCallback = function(cb) {
|
|
return function(res) {
|
|
if(res==null) {
|
|
// expected behaviour for quit
|
|
if(cb!=null){ return cb();}
|
|
}else{
|
|
res.setEncoding('utf8');
|
|
var data = '';
|
|
res.on('data', function(chunk) { data += chunk.toString(); });
|
|
res.on('end', function() {
|
|
if(data == '') {
|
|
// expected behaviour
|
|
return cb()
|
|
} else {
|
|
// something wrong
|
|
if(cb!=null){
|
|
return cb(new Error(
|
|
{message:'Unexpected data in simpleCallback.', data:data}) );
|
|
}
|
|
}
|
|
});
|
|
}
|
|
};
|
|
};
|
|
|
|
// base for all callback handling data
|
|
var callbackWithDataBase = function(cb) {
|
|
return function(res) {
|
|
res.setEncoding('utf8');
|
|
var data = '';
|
|
res.on('data', function(chunk) { data += chunk.toString(); });
|
|
res.on('end', function() {
|
|
var obj;
|
|
try {
|
|
obj = JSON.parse(strip(data));
|
|
} catch (e) {
|
|
return cb(newError({message:'Not JSON response', data:data}));
|
|
}
|
|
if (obj.status > 0) {
|
|
cb(newError(
|
|
{message:'Error response status.',status:obj.status,cause:obj}));
|
|
} else {
|
|
cb(null, obj);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
// retrieves field value from result
|
|
var callbackWithData = function(cb) {
|
|
return callbackWithDataBase(function(err,obj) {
|
|
if(err != null) {return cb(err);}
|
|
if(isWebDriverException(obj.value)) {return cb(newError(
|
|
{message:obj.value.message,cause:obj.value}));}
|
|
cb(null, obj.value);
|
|
});
|
|
};
|
|
|
|
// retrieves ONE element
|
|
var elementCallback = function(cb) {
|
|
return callbackWithDataBase(function(err, obj) {
|
|
if(err != null) {return cb(err);}
|
|
if(isWebDriverException(obj.value)) {return cb(newError(
|
|
{message:obj.value.message,cause:obj.value}));}
|
|
if (!obj.value.ELEMENT) {
|
|
cb(newError(
|
|
{message:"no ELEMENT in response value field.",cause:obj}));
|
|
} else {
|
|
cb(null, obj.value.ELEMENT);
|
|
}
|
|
});
|
|
};
|
|
|
|
// retrieves SEVERAL elements
|
|
var elementsCallback = function(cb) {
|
|
return callbackWithDataBase(function(err, obj) {
|
|
if(err != null) {return cb(err);}
|
|
if(isWebDriverException(obj.value)) {return cb(newError(
|
|
{message:obj.value.message,cause:obj.value}));}
|
|
if (!(obj.value instanceof Array)) {return cb(newError(
|
|
{message:"Response value field is not an Array.", cause:obj.value}));}
|
|
var i, elements = [];
|
|
for (i = 0; i < obj.value.length; i++) {
|
|
elements.push(obj.value[i].ELEMENT);
|
|
}
|
|
cb(null, elements);
|
|
});
|
|
};
|
|
|
|
var newHttpOpts = function(method) {
|
|
var opts = new Object();
|
|
opts.method = method;
|
|
for (var o in this.options) {
|
|
opts[o] = this.options[o];
|
|
}
|
|
opts.headers = {};
|
|
opts.headers['Connection'] = 'keep-alive';
|
|
if (opts.method === 'POST' || opts.method === 'GET')
|
|
opts.headers['Accept'] = 'application/json';
|
|
if (opts.method == 'POST')
|
|
opts.headers['Content-Type'] = 'application/json; charset=UTF-8';
|
|
return opts;
|
|
};
|
|
|
|
// session initialization
|
|
var init = function(desired, cb) {
|
|
var _this = this;
|
|
|
|
//allow desired ovveride to be left out
|
|
if (typeof desired == 'function') {
|
|
cb = desired;
|
|
desired = {};
|
|
}
|
|
|
|
// making copy
|
|
var _desired = {};
|
|
for (var k in desired) {
|
|
_desired[k] = desired[k];
|
|
}
|
|
|
|
// defaulting capabilities when necessary
|
|
for (var k in this.defaultCapabilities) {
|
|
_desired[k] = _desired[k] || this.defaultCapabilities[k];
|
|
}
|
|
|
|
// http options
|
|
var httpOpts = newHttpOpts.apply(this, ['POST']);
|
|
|
|
// authentication (for saucelabs)
|
|
if ((_this.username != null) && (_this.accessKey != null)) {
|
|
var authString = _this.username + ':' + _this.accessKey;
|
|
var buf = new Buffer(authString);
|
|
httpOpts['headers'] = {
|
|
'Authorization': 'Basic ' + buf.toString('base64')
|
|
};
|
|
}
|
|
|
|
// building request
|
|
var req = http.request(httpOpts, function(res) {
|
|
var data = '';
|
|
res.on('data', function(chunk) {
|
|
data += chunk;
|
|
});
|
|
res.on('end', function() {
|
|
if (res.headers.location == undefined) {
|
|
console.log('\x1b[31mError\x1b[0m: The environment you requested was unavailable.\n');
|
|
console.log('\x1b[33mReason\x1b[0m:\n');
|
|
console.log(data);
|
|
console.log('\nFor the available values please consult the WebDriver JSONWireProtocol,');
|
|
console.log('located at: \x1b[33mhttp://code.google.com/p/selenium/wiki/JsonWireProtocol#/session\x1b[0m');
|
|
if (cb)
|
|
cb({ message: 'The environment you requested was unavailable.' });
|
|
return;
|
|
}
|
|
var locationArr = res.headers.location.split('/');
|
|
_this.sessionID = locationArr[locationArr.length - 1];
|
|
_this.emit('status', '\nDriving the web on session: ' + _this.sessionID + '\n');
|
|
|
|
if (cb) { cb(null, _this.sessionID) }
|
|
});
|
|
});
|
|
req.on('error', function(e) { cb(e); });
|
|
|
|
// writting data
|
|
req.write(JSON.stringify({desiredCapabilities: _desired}));
|
|
|
|
// sending
|
|
req.end();
|
|
};
|
|
|
|
// used to build all the methods except init
|
|
var methodBuilder = function(builderOpt) {
|
|
// by default we call simpleCallBack(cb) assuming cb is the last argument
|
|
var defaultCb = function() {
|
|
var args, cb, _i;
|
|
args = 2 <= arguments.length ? __slice.call(arguments, 0,
|
|
_i = arguments.length - 1) : (_i = 0, []), cb = arguments[_i++];
|
|
return simpleCallback(cb);
|
|
};
|
|
|
|
return function(cb) {
|
|
var _this = this;
|
|
|
|
// parsing arguments
|
|
var args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
|
|
// http options init
|
|
var httpOpts = newHttpOpts.apply(this, [builderOpt.method]);
|
|
|
|
// retrieving path information
|
|
var relPath = builderOpt.relPath;
|
|
if (typeof relPath === 'function') { relPath = relPath.apply(this, args) }
|
|
var absPath = builderOpt.absPath;
|
|
if (typeof absPath === 'function') { absPath = absPath.apply(this, args) }
|
|
|
|
// setting path in http options
|
|
if (this.sessionID != null) { httpOpts['path'] += '/' + this.sessionID; }
|
|
if (relPath) { httpOpts['path'] += relPath; }
|
|
if (absPath) { httpOpts['path'] = absPath;}
|
|
|
|
// building callback
|
|
cb = (builderOpt.cb || defaultCb).apply(this, args);
|
|
|
|
// wrapping cb if we need to emit a message
|
|
if (builderOpt.emit != null) {
|
|
var _cb = cb;
|
|
cb = function(res) {
|
|
if (builderOpt.emit != null) {
|
|
_this.emit(builderOpt.emit.event, builderOpt.emit.message);
|
|
}
|
|
if (_cb) { _cb(); }
|
|
};
|
|
}
|
|
|
|
// logging
|
|
_this.emit('command', httpOpts['method'],
|
|
httpOpts['path'].replace(this.sessionID, ':sessionID')
|
|
.replace(this.basePath, '')
|
|
);
|
|
|
|
// building request
|
|
var req = http.request(httpOpts, cb);
|
|
req.on('error', function(e) { cb(e); });
|
|
|
|
// writting data
|
|
var data = '';
|
|
if (builderOpt.data != null) {
|
|
data = builderOpt.data.apply(this, args);
|
|
}
|
|
if (typeof data === 'object') {
|
|
data = JSON.stringify(data);
|
|
}
|
|
req.write(data);
|
|
|
|
//sending
|
|
req.end();
|
|
};
|
|
};
|
|
|
|
exports.simpleCallback = simpleCallback;
|
|
exports.callbackWithData = callbackWithData;
|
|
exports.elementCallback = elementCallback;
|
|
exports.elementsCallback = elementsCallback;
|
|
exports.init = init;
|
|
exports.methodBuilder = methodBuilder;
|
|
|