mirror of
https://github.com/sstent/node.git
synced 2026-01-26 23:22:28 +00:00
605 lines
16 KiB
JavaScript
605 lines
16 KiB
JavaScript
fs = require('fs');
|
|
var builder = require('./builder');
|
|
|
|
var methodBuilder = builder.methodBuilder
|
|
, callbackWithData = builder.callbackWithData
|
|
, elementCallback = builder.elementCallback
|
|
, elementsCallback = builder.elementsCallback
|
|
, __slice = Array.prototype.slice;
|
|
|
|
var protocol = {};
|
|
|
|
protocol.init = builder.init;
|
|
|
|
protocol.status = methodBuilder({
|
|
method: 'GET'
|
|
, absPath: function() { return this.basePath + '/status' }
|
|
, cb: function(cb) { return callbackWithData(cb); }
|
|
});
|
|
|
|
protocol.sessions = methodBuilder({
|
|
method: 'GET'
|
|
, absPath: function() { return this.basePath + '/sessions' }
|
|
, cb: function(cb) { return callbackWithData(cb); }
|
|
});
|
|
|
|
|
|
// alternate strategy to get session capabilities
|
|
// extract session capabilities from session list
|
|
protocol.altSessionCapabilities = function(cb) {
|
|
var _this = this;
|
|
// looking for the current session
|
|
protocol.sessions.apply(this, [function(err, sessions) {
|
|
if (err == null) {
|
|
sessions = sessions.filter(function(session) {
|
|
return session.id === _this.sessionID;
|
|
});
|
|
var _ref;
|
|
return cb(null, (_ref = sessions[0]) != null ? _ref.capabilities : void 0);
|
|
} else {
|
|
return cb(err, sessions);
|
|
}
|
|
}]);
|
|
};
|
|
|
|
protocol.sessionCapabilities = methodBuilder({
|
|
method: 'GET'
|
|
// default url
|
|
, cb: function(cb) { return callbackWithData(cb); }
|
|
});
|
|
|
|
protocol.close = methodBuilder({
|
|
method: 'DELETE'
|
|
, relPath: '/window'
|
|
});
|
|
|
|
protocol.quit = methodBuilder({
|
|
method: 'DELETE'
|
|
// default url
|
|
, emit: {event: 'status', message: '\nEnding your web drivage..\n'}
|
|
});
|
|
|
|
protocol.eval = function(code, cb) {
|
|
code = "return " + code + ";"
|
|
protocol.execute.apply( this, [code, function(err, res) {
|
|
if(err!=null) {return cb(err);}
|
|
cb(null, res);
|
|
}]);
|
|
};
|
|
|
|
protocol.safeEval = function(code, cb) {
|
|
protocol.safeExecute.apply( this, [code, function(err, res) {
|
|
if(err!=null) {return cb(err);}
|
|
cb(null, res);
|
|
}]);
|
|
};
|
|
|
|
protocol.execute = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/execute'
|
|
, cb: function() {
|
|
// parsing args, cb at the end
|
|
var cb, _args, _i;
|
|
_args = 2 <= arguments.length ? __slice.call(arguments, 0,
|
|
_i = arguments.length - 1) : (_i = 0, []), cb = arguments[_i++];
|
|
|
|
return callbackWithData(cb);
|
|
}
|
|
, data: function() {
|
|
// parsing arguments (code,args,cb) with optional args
|
|
var args, cb, code, _args, _i;
|
|
_args = 2 <= arguments.length ? __slice.call(arguments, 0,
|
|
_i = arguments.length - 1) : (_i = 0, []), cb = arguments[_i++];
|
|
code = _args[0], args = _args[1];
|
|
|
|
//args default
|
|
if (typeof args === "undefined" || args === null) {
|
|
args = [];
|
|
}
|
|
|
|
return {script: code, args: args};
|
|
}
|
|
});
|
|
|
|
// script to be executed in browser
|
|
var safeExecuteJsScript = fs.readFileSync( __dirname + "/browser-scripts/safe-execute.js", 'utf8');
|
|
|
|
protocol.safeExecute = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/execute'
|
|
, cb: function() {
|
|
// parsing args, cb at the end
|
|
var cb, _args, _i;
|
|
_args = 2 <= arguments.length ? __slice.call(arguments, 0,
|
|
_i = arguments.length - 1) : (_i = 0, []), cb = arguments[_i++];
|
|
return callbackWithData(cb);
|
|
}
|
|
, data: function() {
|
|
// parsing arguments (code,args,cb) with optional args
|
|
var args, cb, code, _args, _i;
|
|
_args = 2 <= arguments.length ? __slice.call(arguments, 0,
|
|
_i = arguments.length - 1) : (_i = 0, []), cb = arguments[_i++];
|
|
code = _args[0], args = _args[1];
|
|
|
|
//args default
|
|
if (typeof args === "undefined" || args === null) {
|
|
args = [];
|
|
}
|
|
|
|
return {script: safeExecuteJsScript, args: [code, args]};
|
|
}
|
|
});
|
|
|
|
protocol.executeAsync = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/execute_async'
|
|
, cb: function() {
|
|
// parsing args, cb at the end
|
|
var cb, _args, _i;
|
|
_args = 2 <= arguments.length ? __slice.call(arguments, 0,
|
|
_i = arguments.length - 1) : (_i = 0, []), cb = arguments[_i++];
|
|
|
|
return callbackWithData(cb);
|
|
}
|
|
, data: function(code) {
|
|
// parsing arguments (code,args,cb) with optional args
|
|
var args, cb, code, _args, _i;
|
|
_args = 2 <= arguments.length ? __slice.call(arguments, 0,
|
|
_i = arguments.length - 1) : (_i = 0, []), cb = arguments[_i++];
|
|
code = _args[0], args = _args[1];
|
|
|
|
//args default
|
|
if (typeof args === "undefined" || args === null) {
|
|
args = [];
|
|
}
|
|
|
|
return {script: code, args: args};
|
|
}
|
|
});
|
|
|
|
// script to be executed in browser
|
|
var safeExecuteAsyncJsScript = fs.readFileSync( __dirname + "/browser-scripts/safe-execute-async.js", 'utf8');
|
|
|
|
protocol.safeExecuteAsync = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/execute_async'
|
|
, cb: function() {
|
|
// parsing args, cb at the end
|
|
var cb, _args, _i;
|
|
_args = 2 <= arguments.length ? __slice.call(arguments, 0,
|
|
_i = arguments.length - 1) : (_i = 0, []), cb = arguments[_i++];
|
|
|
|
return callbackWithData(cb);
|
|
}
|
|
, data: function(code) {
|
|
// parsing arguments (code,args,cb) with optional args
|
|
var args, cb, code, _args, _i;
|
|
_args = 2 <= arguments.length ? __slice.call(arguments, 0,
|
|
_i = arguments.length - 1) : (_i = 0, []), cb = arguments[_i++];
|
|
code = _args[0], args = _args[1];
|
|
|
|
//args default
|
|
if (typeof args === "undefined" || args === null) {
|
|
args = [];
|
|
}
|
|
|
|
return {script: safeExecuteAsyncJsScript , args: [code, args]};
|
|
}
|
|
});
|
|
|
|
protocol.get = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/url'
|
|
, data: function(url) { return {'url': url}; }
|
|
});
|
|
|
|
protocol.refresh = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/refresh'
|
|
});
|
|
|
|
protocol.forward = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/forward'
|
|
});
|
|
|
|
protocol.back = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/back'
|
|
});
|
|
|
|
protocol.setImplicitWaitTimeout = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/timeouts/implicit_wait'
|
|
, data: function(ms) { return {ms: ms}; }
|
|
});
|
|
|
|
// for backward compatibility
|
|
protocol.setWaitTimeout = protocol.setImplicitWaitTimeout;
|
|
|
|
protocol.setAsyncScriptTimeout = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/timeouts/async_script'
|
|
, data: function(ms) { return {ms: ms}; }
|
|
});
|
|
|
|
protocol.setPageLoadTimeout = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/timeouts/timeouts'
|
|
, data: function(ms) { return {type: 'page load', ms: ms}; }
|
|
});
|
|
|
|
protocol.element = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/element'
|
|
, cb: function(using, value, cb) { return elementCallback(cb); }
|
|
, data: function(using, value) { return {using: using, value: value}; }
|
|
});
|
|
|
|
// avoid not found exception and return null instead
|
|
protocol.elementOrNull = function(using, value, cb) {
|
|
protocol.elements.apply(this, [using, value,
|
|
function(err, elements) {
|
|
if(err == null)
|
|
if(elements.length>0) {cb(null,elements[0]);} else {cb(null,null);}
|
|
else
|
|
cb(err);
|
|
}
|
|
]);
|
|
};
|
|
|
|
// avoid not found exception and return undefined instead
|
|
protocol.elementIfExists = function(using, value, cb) {
|
|
protocol.elements.apply(this, [using, value,
|
|
function(err, elements) {
|
|
if(err == null)
|
|
if(elements.length>0) {cb(null,elements[0]);} else {cb(null,undefined);}
|
|
else
|
|
cb(err);
|
|
}
|
|
]);
|
|
};
|
|
|
|
protocol.elements = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/elements'
|
|
, cb: function(using, value, cb) { return elementsCallback(cb); }
|
|
, data: function(using, value) { return {using: using, value: value}; }
|
|
});
|
|
|
|
protocol.hasElement = function(using, value, cb){
|
|
protocol.elements.apply( this, [using, value, function(err, elements){
|
|
if(err==null)
|
|
cb(null, elements.length > 0 )
|
|
else
|
|
cb(err);
|
|
}]);
|
|
}
|
|
|
|
// convert to type to something like ById, ByCssSelector, etc...
|
|
var elFuncSuffix = function(type){
|
|
res = (' by ' + type).replace(/(\s[a-z])/g,
|
|
function($1){return $1.toUpperCase().replace(' ','');});
|
|
return res.replace('Xpath', 'XPath');
|
|
};
|
|
|
|
// return correct jsonwire type
|
|
var elFuncFullType = function(type){
|
|
if(type == 'css') {return 'css selector'} // shortcut for css
|
|
return type;
|
|
};
|
|
|
|
// from JsonWire spec + shortcuts
|
|
var elementFuncTypes = ['class name', 'css selector','id','name','link text',
|
|
'partial link text','tag name', 'xpath', 'css' ];
|
|
|
|
// adding all elementBy... , elementsBy... function
|
|
|
|
for (var i = 0; i < elementFuncTypes.length; i++) {
|
|
|
|
(function() {
|
|
var type = elementFuncTypes[i];
|
|
|
|
protocol['element' + elFuncSuffix(type)] = function(value, cb) {
|
|
protocol.element.apply(this, [elFuncFullType(type), value, cb]);
|
|
};
|
|
|
|
// avoid not found exception and return null instead
|
|
protocol['element' + elFuncSuffix(type)+ 'OrNull'] = function(value, cb) {
|
|
protocol.elements.apply(this, [elFuncFullType(type), value,
|
|
function(err, elements) {
|
|
if(err == null)
|
|
if(elements.length>0) {cb(null,elements[0]);} else {cb(null,null);}
|
|
else
|
|
cb(err);
|
|
}
|
|
]);
|
|
};
|
|
|
|
// avoid not found exception and return undefined instead
|
|
protocol['element' + elFuncSuffix(type)+ 'IfExists'] = function(value, cb) {
|
|
protocol.elements.apply(this, [elFuncFullType(type), value,
|
|
function(err, elements) {
|
|
if(err == null)
|
|
if(elements.length>0) {cb(null,elements[0]);} else {cb(null,undefined);}
|
|
else
|
|
cb(err);
|
|
}
|
|
]);
|
|
};
|
|
|
|
protocol['hasElement' + elFuncSuffix(type)] = function(value, cb) {
|
|
protocol.hasElement.apply(this, [elFuncFullType(type), value, cb]);
|
|
};
|
|
|
|
protocol['elements' + elFuncSuffix(type)] = function(value, cb) {
|
|
protocol.elements.apply(this, [elFuncFullType(type), value, cb]);
|
|
};
|
|
|
|
})();
|
|
|
|
}
|
|
|
|
protocol.getAttribute = methodBuilder({
|
|
method: 'GET'
|
|
, relPath: function(element, attrName) {
|
|
return '/element/' + element + '/attribute/' + attrName; }
|
|
, cb: function(element, attrName, cb) { return callbackWithData(cb); }
|
|
});
|
|
|
|
protocol.getValue = function(element, cb) {
|
|
protocol.getAttribute.apply(this, [element, 'value', cb]);
|
|
};
|
|
|
|
protocol.clickElement = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: function(element, attrName) {
|
|
return '/element/' + element + '/click'; }
|
|
});
|
|
|
|
protocol.moveTo = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/moveto'
|
|
, data: function(element, xoffset, yoffset) {
|
|
return { element: element, xoffset: xoffset, yoffset: yoffset }; }
|
|
});
|
|
|
|
//@todo simulate the scroll event using dispatchEvent and browser.execute
|
|
/* it's not implemented so taking it out
|
|
protocol.scroll = methodBuilder({
|
|
method: 'POST'
|
|
, relPath:'/moveto'
|
|
, data: function(element, xoffset, yoffset) {
|
|
return { element : element, xoffset : xoffset, yoffset : yoffset }; }
|
|
});
|
|
*/
|
|
|
|
protocol.buttonDown = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/buttondown'
|
|
});
|
|
|
|
protocol.buttonUp = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/buttonup'
|
|
});
|
|
|
|
//{LEFT = 0, MIDDLE = 1 , RIGHT = 2}
|
|
protocol.click = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/click'
|
|
, data: function(button) { return {button: button}; }
|
|
});
|
|
|
|
|
|
protocol.doubleclick = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/doubleclick'
|
|
});
|
|
|
|
//All keys are up at end of command
|
|
protocol.type = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: function(element, keys) {
|
|
return '/element/' + element + '/value'; }
|
|
, data: function(element, keys) {
|
|
if (!(keys instanceof Array)) {keys = [keys];}
|
|
return {value: keys};
|
|
}
|
|
});
|
|
|
|
protocol.keys = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/keys'
|
|
, data: function(keys) {
|
|
if (!(keys instanceof Array)) {keys = [keys];}
|
|
return {value: keys};
|
|
}
|
|
});
|
|
|
|
protocol.clear = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: function(element) { return '/element/' + element + '/clear'; }
|
|
});
|
|
|
|
protocol.title = methodBuilder({
|
|
method: 'GET'
|
|
, relPath: '/title'
|
|
, cb: function(cb) { return callbackWithData(cb); }
|
|
});
|
|
|
|
// element must be specified
|
|
_rawText = methodBuilder({
|
|
method: 'GET'
|
|
, relPath: function(element) { return '/element/' + element + '/text'; }
|
|
, cb: function(element, cb) { return callbackWithData(cb); }
|
|
});
|
|
|
|
// element is specific element, 'body', or undefined
|
|
protocol.text = function(element, cb) {
|
|
var _this = this;
|
|
if (typeof element === 'undefined' || element == 'body' || element === null) {
|
|
protocol.element.apply(this, ['tag name', 'body', function(err, bodyEl) {
|
|
if (err == null) {_rawText.apply(_this, [bodyEl, cb]);} else {cb(err);}
|
|
}]);
|
|
}else {
|
|
_rawText.apply(_this, [element, cb]);
|
|
}
|
|
};
|
|
|
|
// element is specific element, 'body', or undefined
|
|
protocol.textPresent = function(searchText, element, cb) {
|
|
protocol.text.apply(this, [element, function(err, text) {
|
|
if (err) {
|
|
cb(err, null);
|
|
} else {
|
|
cb(err, text.indexOf(searchText) >= 0);
|
|
}
|
|
}]);
|
|
};
|
|
|
|
protocol.acceptAlert = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/accept_alert'
|
|
});
|
|
|
|
protocol.dismissAlert = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/dismiss_alert'
|
|
});
|
|
|
|
protocol.active = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/element/active'
|
|
, cb: function(cb) {
|
|
return callbackWithData(function(e, o) { cb(null, o['ELEMENT'])});
|
|
}
|
|
});
|
|
|
|
protocol.url = methodBuilder({
|
|
method: 'GET'
|
|
, relPath: '/url'
|
|
, cb: function(cb) { return callbackWithData(cb); }
|
|
});
|
|
|
|
|
|
protocol.allCookies = methodBuilder({
|
|
method: 'GET'
|
|
, relPath: '/cookie'
|
|
, cb: function(cb) { return callbackWithData(cb); }
|
|
});
|
|
|
|
/*
|
|
cookie like the following:
|
|
{name:'fruit', value:'apple'}
|
|
optional fields: path, domain, secure, expiry
|
|
check the JsonWire doc for details
|
|
*/
|
|
protocol.setCookie = methodBuilder({
|
|
method: 'POST'
|
|
, relPath: '/cookie'
|
|
, data: function(cookie) {
|
|
// setting secure otherwise selenium server throws
|
|
if ((typeof cookie !== 'undefined' && cookie !== null) &&
|
|
!((typeof cookie !== 'undefined' &&
|
|
cookie !== null ? cookie.secure : void 0) != null)) {
|
|
cookie.secure = false;
|
|
}
|
|
return { cookie: cookie };
|
|
}
|
|
});
|
|
|
|
protocol.deleteAllCookies = methodBuilder({
|
|
method: 'DELETE'
|
|
, relPath: '/cookie'
|
|
});
|
|
|
|
protocol.deleteCookie = methodBuilder({
|
|
method: 'DELETE'
|
|
, relPath: function(name) {
|
|
return '/cookie/' + encodeURIComponent(name); }
|
|
});
|
|
|
|
|
|
// waitForCondition recursive implementation
|
|
var waitForConditionImpl = function(conditionExpr, limit, poll, cb) {
|
|
var _this = this;
|
|
|
|
// timeout check
|
|
if (Date.now() < limit) {
|
|
// condition check
|
|
protocol.eval.apply( _this , [conditionExpr, function(err, res) {
|
|
if(err != null) {return cb(err);}
|
|
if (res == true) {
|
|
// condition ok
|
|
return cb(null, true);
|
|
} else {
|
|
// wait for poll and try again
|
|
setTimeout(function() {
|
|
waitForConditionImpl.apply(_this, [conditionExpr, limit, poll, cb]);
|
|
}, poll);
|
|
}
|
|
}]);
|
|
} else {
|
|
// try one last time
|
|
protocol.eval.apply( _this, [conditionExpr, function(err, res) {
|
|
if(err != null) {return cb(err);}
|
|
if (res == true) {
|
|
return cb(null, true);
|
|
} else {
|
|
// condition nok within timeout
|
|
return cb("waitForCondition failure for: " + conditionExpr);
|
|
}
|
|
}]);
|
|
}
|
|
};
|
|
|
|
// args: (conditionExpr, timeout, poll, cb)
|
|
// timeout and poll are optional
|
|
protocol.waitForCondition = function() {
|
|
// parsing args
|
|
var args, cb, conditionExpr, limit, poll, timeout, _i;
|
|
args = 2 <= arguments.length ? __slice.call(arguments, 0,
|
|
_i = arguments.length - 1) : (_i = 0, []),
|
|
cb = arguments[_i++];
|
|
conditionExpr = args[0], timeout = args[1], poll = args[2];
|
|
|
|
//defaults
|
|
timeout = timeout || 1000;
|
|
poll = poll || 100;
|
|
|
|
// calling implementation
|
|
limit = Date.now() + timeout;
|
|
waitForConditionImpl.apply(this, [conditionExpr, limit, poll, cb]);
|
|
};
|
|
|
|
// script to be executed in browser
|
|
var waitForConditionInBrowserJsScript = fs.readFileSync( __dirname + "/browser-scripts/wait-for-cond-in-browser.js", 'utf8');
|
|
|
|
// args: (conditionExpr, timeout, poll, cb)
|
|
// timeout and poll are optional
|
|
protocol.waitForConditionInBrowser = function() {
|
|
var _this = this;
|
|
// parsing args
|
|
var args, cb, conditionExpr, limit, poll, timeout, _i;
|
|
args = 2 <= arguments.length ? __slice.call(arguments, 0,
|
|
_i = arguments.length - 1) : (_i = 0, []),
|
|
cb = arguments[_i++];
|
|
conditionExpr = args[0], timeout = args[1], poll = args[2];
|
|
|
|
//defaults
|
|
timeout = timeout || 1000;
|
|
poll = poll || 100;
|
|
|
|
// calling script
|
|
protocol.executeAsync.apply( _this, [waitForConditionInBrowserJsScript,
|
|
[conditionExpr,timeout,poll], function(err,res) {
|
|
if(err != null) {return cb(err);}
|
|
if(res != true) {return cb("waitForConditionInBrowser failure for: " + conditionExpr);}
|
|
cb(null, res);
|
|
}
|
|
]);
|
|
};
|
|
|
|
module.exports = protocol;
|